arbisoft brand logo
arbisoft brand logo
Contact Us

A Reality Check: Modern Codebases

Muhammad Abdullah's profile picture
Muhammad Abdullah QureshiPosted on
8-9 Min Read Time

Most of us start our coding journey from the legendary ‘Hello World’ program. Many programming languages showcase their simplicity and beauty through the simplicity and beauty of the Hello World program in them. From there on, we tend to learn a lot of coding that is not just limited to a programming language but also includes many core concepts. Concepts like the runtime complexity, space complexity, the invariant, and so on. Besides all these technical aspects of programming, we also learn how to write clean and manageable code that is both readable and concise.

 

After the Hello World program, we start driving on a practically endless road. There are several crossroads in between where you can decide your future endeavors. You could be a Machine Learning Engineer, a Software Developer, a Frontend Developer, or a Full Stack Developer. The list goes on and on.

 

No matter which set of expertise you choose, you will be working to achieve a code that is a masterpiece in terms of its conciseness, efficiency, and readability. To achieve such greatness, we learn how to write clean code, best practices, trending frameworks, design patterns, tips and tricks, and so on. 

 

Then you jump into the industry and start writing or working on already written code. Here you come to realize that all of this learning was only for the sake of learning, and the senior developers there with more experience than you, with more tools at their hands, with more exposure to the market, write code that is unimaginably far from what you had learnt throughout the ages. The only Design Pattern the codebase has is “Design, Develop, and Ship.”

 

Your Awesome Schema Validation

What a concise and beautiful way to validate your user’s input:

 

const schema = z.object({
  name: z.string().min(1, 'Please enter your name.'),
  email: z
    .string()
    .min(1, 'Please enter an email')
    .email('Please enter a valid email e.g. name@email.com.'),
  phone: z.string().min(7, 'Please enter a phone number.'),
  message: z.string().min(1, 'Please describe the project.'),
});

 

Wake up to reality. The awesome product that your company is super proud of, and you should be grateful to get an opportunity to work on, has no such thing as schema validator. Instead, you have gotten yourself a file with 15000+ lines of conditionals that are validating who knows what. These 15000 lines contain snippets like:

 

export const awesomValidator = (values, t = null) => {
    const errors = {};

    if (!values['offered_date'] || !(values['offered_date'] instanceof Date)) {
        errors['offered_date'] = t ?
            t('DISPLAY_TEXT.ERROR_MESSAGES.DATE_MISSING') : ERROR_MESSAGES.DATE_MISSING;
    }

    if (!values['joining_date'] || !(values['joining_date'] instanceof Date)) {
        errors['joining_date'] = t ?
            t('DISPLAY_TEXT.ERROR_MESSAGES.DATE_MISSING') : ERROR_MESSAGES.DATE_MISSING;
    }

    if (values['send_mail']) {
        if (values['template_id'] === -1) {
            errors['template_id'] = t ?
                t('DISPLAY_TEXT.ERROR_MESSAGES.EMAIL_TEMPLATE_MISSING') : ERROR_MESSAGES.EMAIL_TEMPLATE_MISSING;
        }

        if (isEditorEmpty(values.content)) {
            errors.content = t ?
                t('DISPLAY_TEXT.ERROR_MESSAGES.CONTENT_MISSING') : ERROR_MESSAGES.CONTENT_MISSING;
        } else if (hasInvalidVariables(values.content)) {
            errors.content = t ?
                t('DISPLAY_TEXT.ERROR_MESSAGES.INVALID_VARIABLES') : ERROR_MESSAGES.INVALID_VARIABLES;
        }
    }

     if (values.salary < 0) {
        errors.salary = t ?
            t('DISPLAY_TEXT.ERROR_MESSAGES.INVALID_VALUE') : ERROR_MESSAGES.INVALID_VALUE;
    }
    if (values.salary && !values.accepted_currency) {
        errors.accepted_currency = t ?
            t('DISPLAY_TEXT.ERROR_MESSAGES.FIELD_REQUIRED') : ERROR_MESSAGES.FIELD_REQUIRED;
    }
    if (values.salary < 0) {
        errors.salary = ERROR_MESSAGES.INVALID_VALUE;
    }
    if (values.salary && !values.accepted_currency) {
        errors.accepted_currency = ERROR_MESSAGES.FIELD_REQUIRED;
    }

    return errors;
};

 

Your Top-Notch Network Request Handler

You are well equipped with React-Query and its best practices and whatnot. Wake up to reality. Your company’s marvel doesn’t contain such a thing. 

 

The network requests are handled with Redux. Not the awesome RTK-Query that you leveled up your skills in over the past 2.5 months. It’s not even the Redux Thunks. It’s your team’s Solution Architect's brilliant idea of the cleanest way to handle api calls in the code. 

 

What’s the idea? 

 

Just do the api call and update the redux store. Now your components are rendering 48 times on just visiting them back and forth, because the 5 api calls are sharing the same store’s loading and success status states. Even the error state is common. Now, the solution architects define a way to tell the code which error belongs to what api call. We usually solve the problems that we created ourselves using poor and hastily made decisions.

 

export default (state = initialState, action) => {
    switch (action.type) {
        case REPORT_ACTION_TYPES.INIT:
            return state.merge({
                error: [],
                statusSuccess: false,
                loading: true
            });
        case REPORT_ACTION_TYPES.GET_REPORT_SUCCESSFUL:
            return state.merge({
                report: action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });
         case REPORT_ACTION_TYPES.GET_WORKFLOWS_SUCCESSFUL:
            return state.merge({
                workflows: action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });
        case REPORT_ACTION_TYPES.GET_STATS_SUCCESSFUL:
            return state.merge({
                stats: action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });
        case REPORT_ACTION_TYPES.GET_STAGE_SUCCESS:
            return state.merge({
                stage: action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });

        case REPORT_ACTION_TYPES.GET_OVERVIEW_SUCCESS:
            return state.merge({
                overview: action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });
        case REPORT_ACTION_TYPES.GET_ANALYTICS_SUCCESS: {
            const { response: { data } } = action;

            return state.merge({
                analytics: {
                    ...data,
                error: [],
                statusSuccess: true,
                loading: false
            });
        }
        case REPORT_ACTION_TYPES.GET_RANKINGS_SUCCESS:
            return state.merge({
rankings: ...action.response.data,
                error: [],
                statusSuccess: true,
                loading: false
            });
         default:
            return state;
    }
};

 

Your latest React 19 API

You’re fully equipped with React 19 and its awesome new features that allow you to better handle the failures, loadings, and fetches. 

 

The great product your company has launched is built on React, amazing. Wake up to reality. The project is using React 16. Class Components everywhere, Components wrapped with tens of Higher Order Components. No hooks in sight. Props drilled down to the Earth’s core. Props are injected from somewhere, and no one knows from where; all we know is that there must be an HOC up in the hierarchy injecting these props (optional).

 

export default withStyles(componentStyles)(withTranslation()(
    withIsMobile(withActions(withConfig(memo(Component))), 'md')
));

 

Your Clean and Lean Typescript 5 API

All those sleepless nights learning typescript on top of JavaScript to produce a more robust and error-free code. What types? Wake up to reality. The awesome company showcase is all in JavaScript. There is absolutely no auto-complete working. All you see is a function with argument ‘values’ and nothing else. 

 

Now you figure out the position where this code is being used. Then you traverse up from its caller and reach the point where you finally breathe a sigh of relief because the values are being returned from the ‘abc’ callback. Now all you have to do is check this ‘callback’ and voila, the callback is a network request, and all you see is this:

 

this.props.getSiteGroupsList();

 

Maybe it's just me, but if you find a way to figure out what the response type is, do let me know.

 

Why so Harsh?

Me or reality? I guess both of us. 

 

If you’re with me till now, let me tell you that there is a reason why I decided to keep a harsh tone throughout this blog. The reason is that it depicts reality - the harsh reality. 

 

Most of the codebases are years old, and you have to live with them. No one out there is motivated to do any refactoring or include any new libraries to reduce the code clutter or reduce the tech debt. Everyone is focused on writing code, generating output, and nothing more. 

 

Senior leadership, clients, and advisory committees are all focused on the goal, not the road. But we don’t necessarily have to compromise the goal in order to get a smoother journey. 

 

Why can’t we enjoy the destination and the journey both? Why can’t they both be fun and beautiful? 

 

“I guess we’ll never know” - Kanye West.

 

Takeaway

The purpose of this blog is not to downgrade any project or any developer or anyone else, for that matter. No one hurt me either. I just wanted to share what’s really out there. If your project looks similar to the snippets I’ve shared above, maybe it's time to start working on making things better step by step. 

 

In my blog “Why DX is important and How to Improve Your React Components” I talked about how you can use Divide and Conquer to refactor your thousand lines plus components. The same approach goes for the project as a whole. 

 

Start small and continue to make a big impact.

...Loading

Explore More

Have Questions? Let's Talk.

We have got the answers to your questions.

Newsletter

Join us to stay connected with the global trends and technologies