Создаём одинаковое приложение на двух языках и сравниваем подходы.
🔸 Что делаем
CLI-приложение с 4 командами:
-
list — показать все задачи-
add — добавить задачу-
done — отметить выполненные-
clear — удалить всеФормат хранения:
[ ] заголовок задачи
[*] выполненная задача
🔸JavaScript: Setup
pnpm init
Node v20, ESM модули, без сторонних библиотек. Файл
todo.mjs.Добавить задачу:
async function addTodo(filePath, todoTitle) {
return await useTodoFile(filePath, async (fd) => {
fd.appendFile(`[ ] ${todoTitle}\n`)
})
}Форматированный список:
async function formattedTodos(filePath) {
return await useTodoFile(filePath, async (fd) => {
const content = await fd.readFile('utf8')
return content
.split('\n')
.filter((title) => title)
.map((title, index) => {
const isDone = /^\[\*\]/.test(title)
const rawTitle = title.match(/^\[[\s*]\]\s(.+)/)?.[1]
return `${index + 1} ${isDone ? strikethrough(rawTitle) : rawTitle}`
})
.join('\n')
})
}Отметить выполненной:
async function markDone(filePath, ids) {
return await useTodoFile(filePath, async (fd) => {
const content = await fd.readFile('utf8')
const lines = content.split('\n')
ids.forEach((id) => {
lines[id - 1] = lines[id - 1].replace(/^\[\s\]/, '[*]')
})
await fd.truncate()
await fd.writeFile(lines.join('\n'))
})
}🔸 Gleam: Setup
gleam new gleam_todos
gleam add argv simplifile gleam_community_ansi
Добавить задачу:
pub fn add_todo(file_path: String, title: String) -> Result(Nil, Nil) {
simplifile.append(file_path, "[ ] " <> title <> "\n")
|> result.replace(Nil)
|> result.nil_error
}Форматированный список:
pub fn formatted_todos(file_path: String) -> Result(String, Nil) {
simplifile.read(file_path)
|> result.map(split_to_lines)
|> result.map(format_todo_lines)
|> result.map(join_lines)
|> result.nil_error
}
fn format_todo_lines(lines: List(String)) -> List(String) {
list.index_map(lines, fn(line, index) {
case line {
"[ ] " <> rest -> int.to_string(index + 1) <> " " <> rest
"[*] " <> rest -> int.to_string(index + 1) <> " " <> ansi.strikethrough(rest)
_ -> line
}
})
}Отметить выполненной:
pub fn mark_done(file_path: String, ids: List(Int)) -> Result(Nil, Nil) {
simplifile.read(file_path)
|> result.map(split_to_lines)
|> result.map(fn(lines) { mark_todo_done(lines, ids) })
|> result.map(join_lines)
|> result.try(fn(content) { simplifile.write(file_path, content) })
|> result.nil_error
}🔸 Запуск
JavaScript:
node todo.mjs add "first todo"
node todo.mjs list
Gleam:
gleam run add "first todo"
gleam run list
Итог ⬇️
JavaScript:
- ✅ Знакомый синтаксис
- ✅ Нативная работа с файлами
- ❌ Многословный код
- ❌ Ручная обработка ошибок
Gleam:
- ✅ Чистый, лаконичный синтаксис
- ✅ Result для обработки ошибок
- ✅ Pattern matching вместо регулярок
- ✅ Pipes
|> для цепочек операций- ❌ Менее знакомый синтаксис
Автор предпочитает Gleam за красивый код, мощную обработку ошибок и простые зависимости.
Gleam код читается как описание того, что делает программа, а не как она это делает.
📎 Статья
🎙 Новости
📝 База вопросов
