Debugging Hacks and Tips for Backend Developers

It’s an old story but it’s a well-known fact that in UI development, issues are immediately visible, such as broken displays or unresponsive actions. However, for backend developers, hidden bugs can be a nightmare, often lurking deep within the code. These issues sometimes only emerge in production environments when the data reaches a significant volume. So, how can we protect ourselves and avoid these challenging situations? After nearly six years of experience as a backend developer, I’d like to share some valuable tips that I’ve learned from my failures along the way.

1. Logging

There are several logging libraries that can be used in Spring so take advantage of them to log necessary information, especially information which is related to logical changes. However, be careful with sensitive personal information such as passwords, user account numbers, addresses, etc.; please do not leave any traces in the logs.

Here is the suggested format which might be useful to have a quick understanding where the error occurred.

<datetime><debug_level><thread_name><logger_name><code_line><user_identity> <request_id><request_method><URI_path><response_status><messages>

 

Here is the explanation for the format:

  • datetime: This represents the time when the log is generated, allowing us to pinpoint exactly when the error occurred.
  • debug_level: Each library provides different levels to trace bugs, with common levels including INFO, WARN, ERROR, and DEBUG.
  • thread_name: While often overlooked, this information becomes valuable when monitoring asynchronous processes.
  • logger_name: Each class should have its own log instance. By examining the log name, we can identify the source of the error.
  • code_line: Indicates the exact line of code that caused the error.
  • user_identity: This includes account-related information, helping us determine whether the error is linked to invalid data for a specific user.
  • request_id: This helps distinguish between different incoming requests.
  • request_method: Identifies the specific API being called.
  • URI_path: Helps identify which API endpoint is being accessed.
  • response_status: Indicates whether a normal response was returned or an exception was thrown.
  • messages: Any free text or error messages from the exception class can be included here.

If you use Spring logback, this is the reference for you.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<property name="HOME_LOG" value="logs"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{dd-MM-yyyy HH:mm:ss.SSS} %clr(%-5level){green} %clr([%thread]){magenta} --- %logger{36}.%M %clr([%line]){yellow} %X{email} | %X{request_id} | %X{req.method} | %X{URI} | %X{status_code} | %msg%n
</pattern>
</encoder>
</appender>
    <!-- File Appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>
%d{dd-MM-yyyy HH:mm:ss.SSS} %clr(%-5level){green} %clr([%thread]){magenta} --- %logger{36}.%M %clr([%line]){yellow} %X{email} | %X{request_id} | %X{req.method} | %X{URI} | %X{status_code} | %msg%n
</pattern>
</encoder>
</appender>
<logger name="jp.co.goalist.mystart.console" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

2. Action history table / fields

Most applications don’t include a user activity tracking feature. However, for complex systems involving sales calculations or other computations, I recommend creating a custom table in the database. This allows you to trace the origin of issues if any changes affect previously computed data.

The table should include the following information:

  • Created By: The user who performed the action.
  • Target: The table or object that was affected.
  • Previous Value: The value before the change.
  • Current Value: The value after the change.
  • Created Date / Updated Date: The date and time when the changes were made.
  • Note: Any additional details, such as the reason for the change, especially in cases of errors or special circumstances like a rejection.

3. Meaningful Constant Values

In some cases, we need to examine the database to understand what’s happening. If we use only numbers like 1, 2, or 3 to indicate types or statuses, it can be difficult to grasp the meaning of those fields, especially if they serve as conditions for computing other data. Therefore, whenever possible, it’s better to use meaningful text for constant values.

4. Summary

Sometimes, we need certain strategies to help prevent unknown bugs from unexpected cases, especially when multiple asynchronous processes modify the same field from different screens by multiple users. Since tracking values in real time can be challenging, it’s helpful to leave traces that can assist in identifying whether any processes have gone wrong.

関連記事

カテゴリー:

ブログ

情シス求人

  1. チームメンバーで作字やってみた#1

ページ上部へ戻る