AI-Assisted Development

Project Completion

Generating Comments with Tabnine

In this lesson, we explore how to use Tabnine to generate inline code comments for our application. Our project features a Python backend built with Flask for image compression using OpenCV and a React frontend for the image optimizer. Although our application functions well, it requires proper documentation. We will review approaches and challenges involved in generating inline documentation for large functions.


Documenting the Python Backend

Our Python backend contains an 80-line upload function that processes image uploads. Below is an excerpt of the code:

import logging
from flask import Blueprint, request, jsonify, send_file
import cv2
import numpy as np
import io
import imghdr
from werkzeug.utils import secure_filename
from PIL import Image

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

bp = Blueprint('main', __name__)

@bp.route('/upload', methods=['POST'])
def upload():
    try:
        if 'image' not in request.files:
            logger.error('No image part in the request')
            return jsonify({'error': 'No image part in the request'}), 400
        
        image = request.files['image']
        if image.filename == '':
            logger.error('No image selected for uploading')
            return jsonify({'error': 'No image selected for uploading'}), 400
        
        # Secure the filename
        filename = secure_filename(image.filename)
        # ... additional processing and validations follow ...

Large functions can sometimes confuse auto-generated documentation tools like Tabnine or GitHub Copilot. When generating inline comments or refactoring, these tools might incorrectly suggest the removal of crucial components, such as import statements or logging configurations, which could break the application.

Best Practice

For large functions, consider manually inserting docstrings rather than completely relying on auto-generated comments.

A practical approach is to document the function using a clear docstring at its beginning. Below is an example of how you could document the upload function:

@bp.route('/upload', methods=['POST'])
def upload():
    """
    Handles image upload, validation, and processing.

    This function processes a POST request containing an image file. It validates the presence of the image,
    ensures a filename is provided, secures the filename, and performs further validations. If all checks pass,
    the image is processed using OpenCV based on a quality parameter and returned as binary data.

    Parameters:
        request (flask.Request): The incoming request containing the image file and quality parameter.

    Returns:
        flask.Response: A response object containing the processed image as binary data on success,
        or a JSON error response if validation fails.
    """
    try:
        # Check if image is present in the request
        if 'image' not in request.files:
            logger.error('No image part in the request')
            return jsonify({'error': 'No image part in the request'}), 400
        
        image = request.files['image']

        # Check if the image filename is empty
        if image.filename == '':
            logger.error('No image selected for uploading')
            return jsonify({'error': 'No image selected'}), 400

        # Secure the filename
        filename = secure_filename(image.filename)
        # ... additional processing and image validations follow ...

When auto-generating documentation, tools might try to refactor or remove parts of the code, especially for lengthy functions. Breaking down larger functions into smaller, modular functions enhances both code readability and documentation quality. If refactoring isn't an option, manually reviewing and editing the generated documentation is essential to maintain functionality.

Warning

Always verify that auto-generated documentation does not remove essential code segments like import statements or logging configurations.


Documenting the React Frontend

The React frontend of our application also contains functions that manage intricate logic. For instance, the main App component handles state management for image selection, file size formatting, and interaction with the image optimizer API. Below is an excerpt from the React code:

import { useState, useEffect } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';

function App() {
  const [count, setCount] = useState(0);
  const [selectedImage, setSelectedImage] = useState(null);
  const [selectedImageUrl, setSelectedImageUrl] = useState(null);
  const [selectedImageSize, setSelectedImageSize] = useState(null);
  const [quality, setQuality] = useState(80);
  const [optimizedImageUrl, setOptimizedImageUrl] = useState(null);
  const [optimizedImageSize, setOptimizedImageSize] = useState(null);

  const formatFileSize = (bytes) => {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  };

  const handleImageSelect = (e) => {
    const file = e.target.files[0];
    if (file) {
      // Handle file selection logic
    }
  };

  return (
    <div>
      <main>
        {/* JSX and UI elements go here */}
      </main>
    </div>
  );
}

export default App;

In auto-generated documentation workflows, tools may attempt to remove or alter necessary components such as import statements or the export default declaration. To prevent such issues, you can manually insert doc comments at key locations. This is an example for the App component:

/**
 * Main application component for the Image Optimizer.
 *
 * This component handles image uploading, allows the user to set an image quality parameter,
 * and communicates with the backend to retrieve an optimized image. It also displays both the
 * original and optimized image sizes in a human-readable format.
 *
 * @component
 * @returns {JSX.Element} The rendered application component.
 */
function App() {
  // ... component code remains unchanged ...
}

By inserting these remarks manually, you ensure that essential code remains intact and the documentation is accurate, clear, and maintainable.


Conclusion

This lesson demonstrates the challenges of using AI documentation tools like Tabnine with large functions and multi-file applications. The key takeaways include:

  • Auto-generated comments for large functions may inadvertently lead to code changes.
  • Manual insertion of documentation is beneficial, especially for critical functions.
  • Refactoring large functions into smaller, modular components is a best practice that simplifies both the codebase and the documentation workflow.
  • Always verify that auto-generated documentation does not remove vital code segments such as imports, exports, or logging setups.

By understanding these nuances, you can effectively document both your Python backend and React frontend, ensuring that your code remains clear and maintainable as your project grows.

Happy documenting!

Watch Video

Watch video content

Previous
Wiring up Our Project