ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

832401304 陈颀桢 Software Engineering Practice: Front-End and Back-End Separation Calculator System

832401304 陈颀桢 Software Engineering Practice: Front-End and Back-End Separation Calculator System 832401304陈颀桢 First Assignment: A Front-End/Back-End Separated Calculator SystemThis article documents CalcFlow, a calculator built for the first Software Engineering Practice assignment. It covers the source repositories, live demo, feature screenshots, design decisions, implementation, and deployment checks.Table of ContentsCourse Information and Assignment RequirementsGitHub Repositories and Code StandardsLive Demo and Testing InstructionsPSP TableFinished ProductDesign and ImplementationKey Code and ExplanationsDeployment and VerificationAdditional Features and LimitationsPersonal ReflectionCourse Information and Assignment RequirementsItemDescriptionCourseSoftware Engineering PracticeAssignmentBuild a calculator with separate front and back ends. The back end calculates results and stores history in a database.ObjectivesUnderstand HTTP APIs, expression processing, database persistence, and cooperation between the front end and back end.DeadlineOctober 7, 2026, 23:59 (China Standard Time)Other referencesFirst assignment requirements published by teaching assistant Zhuo GenghuaGitHub Repositories and Code StandardsFront-end repository: grrrced/calculator_frontendBack-end repository: grrrced/calculator_backendFront-end code standard: codestyle.mdBack-end code standard: codestyle.mdLive Demo and Testing InstructionsPublic calculator: Open CalcFlowBack-end health endpoint: Railway API healthOpen the calculator, enter an expression, and click “” or press Enter. The following cases can be checked:128→ 20,18-7→ 11,6*7→ 42,14/2→ 7,0.10.2→ 0.3,12*3→ 7,(12)*3→ 9, and3*-2 4→ -2. Entering1*2or1/0displays an error. After a successful calculation, the result appears in history. Refresh the page to check that the history is loaded again; use the search field to filter loaded records and the “×” button beside a record to delete that specific entry. The upper-right button changes the theme. When the expression field has focus, Enter calculates and Esc clears the input.The expressions, error messages, history after a browser refresh, search, deletion followed by another refresh, theme switching, and keyboard shortcuts were checked on the public page on October 5, 2026. Persistence after a back-end restart has not yet been tested. The back-end service and its database volume must remain available during grading.PSP TableThe figures below are an illustrative, retrospective workload estimate for a third-year student with basic programming experience who is building a separated front-end/back-end application for the first time. Neither column is an original pre-development plan or a measured record of time actually spent. The last column describes work covered by the estimate; it does not prove that the work took the stated time. Without original time logs, an actual plan-versus-result deviation cannot be calculated.PhaseReference plan (minutes; drafted afterward)Reference time with debugging (minutes; not measured)Work covered by the estimateRequirements analysis4050Read the assignment and identify the four required feature groups and acceptance checks.System design6070Define front-end/back-end responsibilities, API responses, and project structure.Front-end development150180Build input, buttons, result display, history, and error feedback.Back-end API development120140Implement routes, input checks, JSON responses, and CORS.Expression parser120170Handle precedence, parentheses, unary signs, and invalid input.Database design4050Create the SQLite table and initialize the database connection.History features6080Save successful calculations, query records, and delete by ID.Integration60100Check API URLs, request bodies, and response fields.Testing and fixes90120Check arithmetic, compound expressions, errors, and history behavior.Deployment60140Publish GitHub Pages, deploy Railway, and configure the database path.Blog writing90120Prepare screenshots, API and code explanations, and project review.Total8901220Approximately 14 hours 50 minutes and 20 hours 20 minutes, respectively.Finished ProductThe following 16 screenshots were captured from the deployed application. They cover the main calculator functions, compound expressions, error handling, history, and additional features. Some screenshots include records left by earlier test cases.Figure 1: Main InterfaceThe page has a calculator area and a history area. It shows the back-end connection status, expression input, buttons, and saved records.Figure 2: AdditionEntering128displays 20. The same expression and result appear in history.Figure 3: SubtractionEntering18-7returns 11, checking both the calculation endpoint and the page display.Figure 4: MultiplicationEntering6*7returns 42. The interface may show a multiplication sign, while the request uses “*”.Figure 5: DivisionEntering14/2returns 7, matching the result returned by the back end.Figure 6: Decimal NumbersEntering0.10.2displays 0.3, demonstrating decimal expression handling.Figure 7: Operator PrecedenceEntering12*3returns 7 because multiplication is evaluated before addition.Figure 8: ParenthesesEntering(12)*3returns 9. Compared with Figure 7, this demonstrates how parentheses change the calculation order.Figure 9: Unary Plus and MinusEntering3*-2 4returns -2. This checks a negative multiplication operand and a unary plus sign.Figure 10: Invalid ExpressionEntering1*2displays an expression error from the back end. It is not stored as a successful calculation.Figure 11: Division by ZeroEntering1/0displays a division-by-zero error and produces no valid result.Figure 12: History After a Browser RefreshAfter refreshing the browser, the input returns to its initial state while history is loaded again from the back end. The earlier record1234555 12400is still present. This checks a browser refresh, not a back-end restart.Figure 13: History SearchTyping1234555into the history search box filters the loaded list to the record with result 12400. Search covers loaded records, not the entire database.Figure 14: Delete a Specific RecordWith the same search filter active, clicking the record’s delete button causes the page to display “No matching records.” The front end sends a deletion request to the back end.Figure 15: History After Deletion and Another RefreshAfter the deletion, a second browser refresh reloads history from the back end. The1234555record no longer appears, while other records remain. The item was deleted from the database rather than hidden only on the page.Figure 16: Dark ThemeClicking the theme button in the upper-right corner switches the page to a dark appearance. The selection lasts only for the current page visit.Design and ImplementationRequirements and Separation of ResponsibilitiesThe assignment requires four arithmetic operations, compound expressions, decimals, parentheses, unary signs, error handling, database-backed history, and deletion of a specific record. Two central constraints are that the final result must be calculated by the back end and that history must be stored in a back-end database.The front end uses HTML, CSS, and vanilla JavaScript. It collects expressions, sends HTTP requests, and displays results and history. The back end uses the Python standard library to provide a JSON API, while SQLite stores calculation records. The two parts are kept in separate GitHub repositories, each with its own README and code standard.Functional structure:CalcFlow ├── Front end: expression input - HTTP request - result/error/history display ├── HTTP API: validation, routing, JSON responses, CORS ├── Calculator: tokens, precedence, parentheses, unary signs, division-by-zero checks └── Data layer: SQLite insert, query, delete one record, clear all recordsA successful request follows this sequence: the front end sends an expression; the back end validates, parses, and calculates it; the back end saves the result; the back end returns the result; and the front end updates the display and reloads history. The browser has no implementation that independently calculates the final answer.Front-End and Back-End DesignThe interface separates calculation from history. Users can type in the expression field or use calculator buttons. Multiplication and division buttons may display “×” and “÷”, but add “*” and “/” to the expression sent to the API. While a request is pending, the interface shows a waiting state. On success it displays the response’s result; on failure it displays the error message. History expressions are escaped before being inserted into HTML so that input is not interpreted as page markup.The back end separates HTTP handling in server.py, expression processing in calculator.py, and SQLite operations in database.py. This keeps UI changes independent of parsing rules and separates API behavior from database access.API Design and InteractionMethod and pathPurposeMain responseGET /api/healthService health check200 with a service name and success flagPOST /api/calculateSubmit an expression201 on success; 400 for an invalid expressionGET /api/history?limit100Retrieve recent history200 with an items arrayDELETE /api/history/{id}Delete one record200 on success; 404 if no such record existsDELETE /api/historyClear all records200 with the deleted-record countFor example, a request body of {“expression”:“(12)*3”} returns success, id, expression, result, and createdAt after a successful calculation; result is 9, while the ID and timestamp are generated by the back end. Division by zero returns HTTP 400 with {“success”:false,“message”:“Division by zero is not allowed”}. The front end checks both the HTTP status and the success field.The two services have different origins, so the back end returns CORS headers and handles OPTIONS preflight requests. The current allowed origin is “*”, suitable for this account-free course demo. The application does not provide user accounts or separate histories for different visitors.Database and HistoryThe calculation_history table contains:FieldTypeMeaningidINTEGER primary key, autoincrementUnique ID used to delete a recordexpressionTEXT, not nullSubmitted expression with surrounding whitespace removedresultREAL, not nullResult calculated by the back endcreated_atTEXT, not nullCreation time in UTC ISO formatOn first startup, the back end creates the data directory, database, and table. Only successful calculations are saved. History is returned in descending ID order; the default is the 100 most recent entries, and the limit parameter is restricted to 1–500. Front-end search filters only the records already loaded.Deletion by ID uses a parameterized SQL statement. After deletion, the front end requests the latest history again. Clearing history deletes all records in the back-end database. A browser refresh triggers a new history API request rather than relying on browser storage.Expression Parsing and Error HandlingThe parser first turns the input into numeric, operator, and parenthesis tokens. It then processes expression - term - unary - primary recursively. The expression level handles addition and subtraction, term handles multiplication and division, unary handles positive and negative signs, and primary handles numbers and parentheses. Therefore12*3evaluates multiplication first,(12)*3evaluates the parentheses first, and3*-2treats “-2” as a negative operand. Operators at the same level are processed from left to right.The implementation does not call eval or exec. Inputs are limited to 200 characters and 100 tokens. Unknown characters, missing operands, mismatched parentheses, and division by zero raise ExpressionError. The back end rejects non-finite results. It uses floating-point arithmetic and rounds results to 12 decimal places, so it is a standard calculator rather than an arbitrary-precision system.Empty input, API configuration, and network-error messages in the front end improve usability but do not replace server-side validation. Database and infrastructure errors are not all mapped to one standardized business error; this remains an area for improvement.Key Code and ExplanationsThe following short excerpts come from the project; some line breaks have been adjusted for readability.1. Send the Expression and Use the Back-End Resultconstdataawaitrequest(/calculate,{method:POST,body:JSON.stringify({expression})});resultOutput.textContentString(data.result);Only the expression is sent. The displayed result comes directly from the response. The request() helper uses fetch and parses JSON; after calculation, loadHistory() retrieves the saved record instead of constructing a fake history item in the browser.2. Calculate, Save, and Respond in That Orderexpressionexpression.strip()resultcalculate(expression)recordrepository.add(expression,result)self._send_json({success:True,**record},HTTPStatus.CREATED)This order ensures that the history result comes from the same back-end calculation. If calculation raises an expression error, repository.add() is not called.3. Handle Unary Signs Separatelydefparse_unary(self)-float:ifself.current()isnotNoneandself.current().kindin(,-):operatorself.consume(self.current().kind).kind valueself.parse_unary()returnvalueifoperatorelse-valuereturnself.parse_primary()The multiplication and division layer calls the unary layer to read its operands. Thus the minus sign in3*-2is understood as part of the operand, rather than a binary subtraction with a missing left operand.4. Insert History with SQL Parameterscursorconnection.execute(INSERT INTO calculation_history(expression, result, created_at) VALUES (?, ?, ?),(expression,result,timestamp),)The SQL statement and expression data remain separate, preventing user input from being concatenated into SQL. Queries and deletions also use parameters, and the connection context commits a successful transaction.Deployment and VerificationThe front end is published with GitHub Pages, and the back end runs on Railway. A Dockerfile builds the back-end Python 3.12 container. The service listens on 0.0.0.0 and reads Railway’s PORT environment variable. A persistent volume is mounted at /data, the SQLite path is /data/calculator.sqlite3, and the health endpoint is /api/health.The front-end config.js chooses the API URL according to the environment: local development uses http://127.0.0.1:8000/api, while the public site uses https://calculatorbackend-production-1bcb.up.railway.app/api. The address 127.0.0.1 refers to the visitor’s own device and cannot serve as a public back-end URL for the teaching assistant.On October 5, 2026, 14 public API checks passed, covering the health endpoint, CORS preflight, eight types of expressions, invalid input, division by zero, history retrieval, and deletion by ID. The page, scripts, and stylesheet also returned HTTP 200, and the online configuration contained the correct back-end URL. Browser checks covered arithmetic, compound expressions, error feedback, history after refresh, search, deletion followed by refresh, theme switching, and Enter/Esc. History persistence after a back-end restart has not yet been tested; a configured volume is not presented as proof of a successful restart test.Deployment required three separate pieces: static page hosting, a running back-end process, and database storage. A GitHub repository is a source-code address, while GitHub Pages serves only the static front end. The back end must run separately and respect the platform-assigned port. SQLite stored only in a temporary container directory could be lost, so the deployment uses a persistent volume. These configuration decisions do not prove every long-running failure scenario has been tested.At the time of deployment, the Railway account showed a 30-day or USD 5 trial credit and no paid plan. Service status and remaining credit should be checked during the grading period.Additional Features and LimitationsHistory search filters the most recent 100 records loaded by default. It does not search the entire database, and there is no pagination interface.The theme button switches between light and dark styles for the current page visit. The choice is not saved across refreshes.When the expression field has focus, Enter calculates and Esc clears the input. The calculation still takes place on the back end.“Clear history” deletes all records from the current database. All visitors currently share one history table because the application has no accounts.The history-search and theme-switching screenshots demonstrate the corresponding features. Enter and Esc were checked in the browser. The clear-all operation is implemented in code but was not covered by this set of screenshots or the online interaction checks. Possible improvements include paginated history, per-user records, saved theme preferences, and more consistent handling of service failures.Personal ReflectionThe most useful lesson from this project is that the front-end repository, public page, and back-end API have different roles and addresses. During deployment, the public page once returned 404. After it became accessible, the back-end health endpoint and the public API URL still needed separate checks. A page loading successfully does not prove that calculation, error handling, and history retrieval work, so testing must use specific input cases.Compound expressions are easier to mishandle than a single arithmetic operation. The implementation separates addition and subtraction, multiplication and division, unary signs, and parentheses in a recursive-descent parser. Comparing12*3with(12)*3makes precedence visible, while3*-2, decimals, invalid expressions, and division by zero exercise important edge cases. A useful next learning step is to trace these examples through the parser functions and explain each call.History requires checking both the visible page and the database state. The back end saves successful calculations to SQLite, and the page queries history again after a refresh. Deleting a specific record and refreshing once more verifies that the record was removed from the database rather than merely hidden in the UI. Persistence after a back-end restart still needs a separate test. Shared history across visitors and unsaved theme preferences are also limitations to address later.There are no original time logs for this project, so the PSP figures above are a workload example, not evidence of actual efficiency. For the next assignment, the tasks should be broken down and estimated before implementation, with time recorded after each phase. Another goal is to reproduce the local startup and essential tests independently, so that the project can be explained, debugged, and modified rather than merely run.
返回列表