Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CLI (application package)

This is a port of the OOP to FP-first style of the official Dart learn series. (see OOP-to-FP architectural map)

Glossary

OOP style - Object Oriented Programming style
FP style - Functional Programming style

NOTE: From this point in time and onwards, the Glossary applies to the remaining part of this document as follows:

Running CLI

From this project's root, run the following command:

dart run cli:main search "Hello, World" >> search_history.txt

This command will redirect and append standard output to the pre-defined search_history.txt found at the root of this project; NOTE: redirection is optional but it provides the developer with a means of traversing.

Troubleshooting

Read this article - Application package on Windows platform

Testing CLI

From this project's root, run the following command:

dart run test/test_cli.dart

Remember: Testing is fundamentally an aggressive attempt to break your own code while writing the test suite: if you actively tried to break your application by testing invalid inputs, missing files, and/or network drops, and your core logic handled every single one safely, then seeing "All tests passed!" is well-earned peace of mind.

OOP-to-FP architectural map

Concept Official Tutorial (OOP-first) Our architecture (FP-first with minimum footprint of OOP) Benefits
Data Models class with mutable properties. typedef Records (e.g., Summary). Guarantees immutability and requires zero boilerplate.
JSON Parsing factory constructors (e.g., fromJson) with manual type casting. Pure functions (e.g., extractSummary) using Pattern Matching. Validates structure and types safely in a single expression.
Command Routing if/else chains checking raw strings. switch expressions over a sealed class (AppCommand). The compiler enforces exhaustiveness (you can't forget to handle a command).
Side Effects (I/O) Direct calls to stdout.writeln and stdin.readLineSync inside core logic. Injecting onOutput and onInput functions at the application boundary. Isolates messy real-world interactions from pure internal logic.
Network Calls Hardcoded http.get inside processing functions. Injecting onFetchSummary into executeCommand. Makes the core router fully deterministic.
Error Handling Scattered try/catch blocks throwing Exceptions. Returning a (Summary?, String?) at the application boundary Errors become predictable data, eliminating hidden crashes.

Eventually, by moving all the unpredictable elements (like stdout) to the very top of main.dart, we transformed executeCommand from an untestable, side-effect-heavy function into a pure, predictable core.

Examples of “application boundary”:

  • Making an HTTP network request (servers crash, Wi-Fi drops)
  • Reading a file from the hard drive (the file might be locked or deleted).
  • Querying a database (the connection might time out).

Summary

We have successfully built a purely functional CLI application. The logic is separated from the side effects, errors are treated as data, and JSON is parsed safely using pattern matching without throwing exceptions!

Credits to free-tier AI tools such as Google Gemini, ChatGPT, et al. for putting me on the right track with Dart syntax, good practices of Functional programming style, you name it!

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages