И мусор в логах го. То есть искать не по типам ошибок (Rust, C#это элементарно), а по конкретным сообщениями. Как там ELF настраивать в таких условиях даже не знаю.
Мрак
Но никто так же делает. Просто сервисы долго не поддерживаются, переписывают полностью вместе с ELF настройками.
Свистоперделки пожалуйста, только не пишите на го долгоживущий код.
Вы спросите, как же пишут долгоживущие проекты вроде кубера? Всё плохо: там полно кастомных слоёв-костылей поверх языка.
В частности костыль для обработки ошибок, в кубере свои типизированные ошибки через k8s.io/apimachinery/pkg/api/errors
type StatusError struct {
ErrStatus metav1.Status
}
// metav1.Status содержит Reason, Code, Message
Так что из-за таких сложностей написание кубер на Go сложнее чем если бы он был на Rust. С использованием LLM, конечно) это сильно снижает порог входа в Rust
Много чего нет. Вот более полный паттерн, мой любимый
Обработка ошибок не загрязняет бизнес логику. Функция read_port - две строки чистой логики, оба ? невидимо делают конвертацию через From. Вся механика ошибок вынесена в определения типов, которые живут отдельно.
В Go та же функция - половина тела это if err != nil { return ... }. Обработка ошибок перемешана с логикой 1:1
Это то что Скотт Влашин называет "railway oriented programming" - happy path читается линейно, а ошибочный путь идет параллельно и не мешает
Аналог в веб: main() - контроллер, read_port - сервис
use std::fs;
use std::num::ParseIntError;
use thiserror::Error;
#[derive(Debug, Error)]
enum ConfigError {
#[error("failed to read config")]
Io(#[from] std::io::Error),
#[error("failed to parse port")]
Parse(#[from] ParseIntError),
}
fn read_port(path: &str) -> Result<u16, ConfigError> {
let content = fs::read_to_string(path)?; // IoError -> ConfigError::Io автоматически
let port = content.trim().parse::<u16>()?; // ParseIntError -> ConfigError::Parse автоматически
Ok(port)
}
fn main() {
match read_port("/etc/app.port") {
Ok(port) => println!("port: {port}"),
Err(e) => eprintln!("Error: {e}"),
}
}
И аналог
package main
import (
"errors"
"fmt"
"os"
"strconv"
)
type ConfigError struct {
Op string
Err error
}
func (e *ConfigError) Error() string {
return fmt.Sprintf("%s: %v", e.Op, e.Err)
}
func (e *ConfigError) Unwrap() error {
return e.Err
}
func readPort(path string) (uint16, error) {
content, err := os.ReadFile(path)
if err != nil {
return 0, &ConfigError{Op: "failed to read config", Err: err}
}
port, err := strconv.ParseUint(string(content), 10, 16)
if err != nil {
return 0, &ConfigError{Op: "failed to parse port", Err: err}
}
return uint16(port), nil
}
func main() {
port, err := readPort("/etc/app.port")
if err != nil {
var ce *ConfigError
if errors.As(err, &ce) {
fmt.Fprintf(os.Stderr, "Config error: %v\n", ce)
}
return
}
fmt.Printf("port: %d\n", port)
}
Эргономика - главное отличие. В Rust компилятор заставляет обработать каждый вариант ошибки (match должен быть исчерпывающим). Добавил вариант в enum - компилятор покажет все места где не обработал. В Go ошибка это error интерфейс, забыл проверить конкретный тип - узнаешь в проде
Но в бедной бизнес логике - в мире го - это не существенно
Если сервис - CRUD с минимальной логикой, типичный микросервис на 5 эндпоинтов, то Go-шный бойлерплейт терпим, а Rust-овые типы избыточны. Проблемы начнутся при росте сложности (рост числа вариантов ошибок, числа слоёв)
Аналогия с автомобилем совсем плохая. Другая связность, нет версионирования, нет постоянных доработок... Если вы хотели поговорить про контракты то какой-то узкий случай получился: описан только механизм связывания (wiring), пропущена семантика контрактов и обработка нарушений. Получился «контракт без обязательств» — красивая диаграмма, которая не гарантирует корректности Указан только один "лучший" способ/шаблон. Почему лучший, при каких условиях. Ничего этого нет.
Недостатком документации является вторичность. Код первичен. Если вы про требования, то LLM не может собрать их. Тесты сделанные по коду годятся только для регресса, так как не несут новой информации. Если test first - полезно, но в основном в leetcode подобных задачах. В общем, так себе польза
Выше рынка в мелких командах (значит, несколько ролей сразу) с ответственной работой. И туда чаще по знакомству. Либо это что-то нестабильное, проектная работа или стартап.
Ещё примеры
Финтех (банки помельче, биржи) - часто выше рынка, особенно на senior+
Gamedev - переезд прилагается)
Зарубежная удаленка - очевидно, но сейчас сложнее с оплатой
Продуктовые компании с венчурным финансированием - пока деньги есть, платят щедро, риски большие
Яндекс платит ниже рынка потому что может - бренд, строчка в резюме, внутренняя школа. Люди идут за опытом и нетворком.
Зачем?
Для создания высокотехнологичных приложений требуются таксисты на своём транспорте
Это эвфемизм проектной работы?. Год и работы нет. Обалдеть
И мусор в логах го. То есть искать не по типам ошибок (Rust, C#это элементарно), а по конкретным сообщениями. Как там ELF настраивать в таких условиях даже не знаю.
Мрак
Но никто так же делает. Просто сервисы долго не поддерживаются, переписывают полностью вместе с ELF настройками.
Свистоперделки пожалуйста, только не пишите на го долгоживущий код.
Вы спросите, как же пишут долгоживущие проекты вроде кубера? Всё плохо: там полно кастомных слоёв-костылей поверх языка.
В частности костыль для обработки ошибок, в кубере свои типизированные ошибки через
k8s.io/apimachinery/pkg/api/errorsТак что из-за таких сложностей написание кубер на Go сложнее чем если бы он был на Rust. С использованием LLM, конечно) это сильно снижает порог входа в Rust
Много чего нет. Вот более полный паттерн, мой любимый
Обработка ошибок не загрязняет бизнес логику. Функция read_port - две строки чистой логики, оба ? невидимо делают конвертацию через From. Вся механика ошибок вынесена в определения типов, которые живут отдельно.
В Go та же функция - половина тела это if err != nil { return ... }. Обработка ошибок перемешана с логикой 1:1
Это то что Скотт Влашин называет "railway oriented programming" - happy path читается линейно, а ошибочный путь идет параллельно и не мешает
Аналог в веб: main() - контроллер, read_port - сервис
И аналог
Эргономика - главное отличие. В Rust компилятор заставляет обработать каждый вариант ошибки (match должен быть исчерпывающим). Добавил вариант в enum - компилятор покажет все места где не обработал. В Go ошибка это error интерфейс, забыл проверить конкретный тип - узнаешь в проде
Но в бедной бизнес логике - в мире го - это не существенно
Если сервис - CRUD с минимальной логикой, типичный микросервис на 5 эндпоинтов, то Go-шный бойлерплейт терпим, а Rust-овые типы избыточны. Проблемы начнутся при росте сложности (рост числа вариантов ошибок, числа слоёв)
Аналогия с автомобилем совсем плохая. Другая связность, нет версионирования, нет постоянных доработок...
Если вы хотели поговорить про контракты то какой-то узкий случай получился:
описан только механизм связывания (wiring), пропущена семантика контрактов и обработка нарушений. Получился «контракт без обязательств» — красивая диаграмма, которая не гарантирует корректности
Указан только один "лучший" способ/шаблон. Почему лучший, при каких условиях. Ничего этого нет.
Недостатком документации является вторичность. Код первичен.
Если вы про требования, то LLM не может собрать их.
Тесты сделанные по коду годятся только для регресса, так как не несут новой информации. Если test first - полезно, но в основном в leetcode подобных задачах.
В общем, так себе польза
Ориентация на быстрые деньги.
В условиях нестабильности это разумно.
Заберите у автора карандаш!
https://habr.com/ru/companies/piter/articles/1007448/
Главы 2-6 прочитайте и поймёте зачем квадратики и стрелочки (архитектурные свойства систем)
Потом можно 12, 18 например
А потом уже стрелочки рисовать
Перевод)
Just as important, without all these wonderfully confusing notions of infinity, how do you keep the riff-raff out of math?
Так опросы и показывали:
LLM сильнее всего ускоряет те задачи, которые он и не пытался бы делать без неё. То есть почти не нужные.
В смысле в России геймдева нет. Но можно найти связи и уехать туда где будут платить
Выше рынка в мелких командах (значит, несколько ролей сразу) с ответственной работой. И туда чаще по знакомству. Либо это что-то нестабильное, проектная работа или стартап.
Ещё примеры
Финтех (банки помельче, биржи) - часто выше рынка, особенно на senior+
Gamedev - переезд прилагается)
Зарубежная удаленка - очевидно, но сейчас сложнее с оплатой
Продуктовые компании с венчурным финансированием - пока деньги есть, платят щедро, риски большие
Яндекс платит ниже рынка потому что может - бренд, строчка в резюме, внутренняя школа. Люди идут за опытом и нетворком.
Свободен, гуляй
И это пройдет©
Ну значит, я всегда был архитектор тугодум
Алго не для меня. Архитектура и экономика проекта - моё.
Привет, МАИ (ТУ)!
Прикладная математика 98 год
Где тег юмор?
Да, это самый честный ответ, пожалуй