Самый кошерный способ лабать веб-сервисы

agent007new

Какой щас самый крутой способ лабать веб-сервисы (ну которые потом аяксом будет кто-нить дергать)? Тот, который знаешь - это понятно. Вопрос чисто абстрактный - никакой конкретной задачи не стоит. Питон с джанго, фласком, там еще чем, жаба, го, еще что? А то щас наплодилось языков и фреймворков и вот какая из этих связок "самая-самая"? Так, ради флуда

YUAL

на python c фреймворком bottle очень удобно лабать рест-костыли. мне тут понадобилось как-то по работе для пресейла мобильных и браузерных приложений сделать бэкэнд. можно было развернуть клон одной из боевых платформ (несколько монстроузных джава-бегемотов, одно ктухоподобное сишное приложение, пара баз данных), но я забил и на путоне за пол часа наваял затычки для всех нужных методов и всё помещается в два файла - фреймворк и затычка.

uncle17

А что надо-то? Какой API?
XML и JSON отдавать большого ума не надо.

agent007new

Да ничего конкретного - просто, чтобы быть в тренде, на чем щас лабают, а то расплодилось всего. Наверное, стандарт - json, сходить в какое-нить хранилище и т.д.

6yrop

ASP.NET

agent007new

А комменты какие-нить будут, чем он крут и круче остальных? Так я сам могу пару десятков названий написать

6yrop

Няшный C#. ReSharper. Controllable Query. Ну или Linq, но я не рекомендую.

0000

NodeJS + Express :D

agent007new

Опять, хотелось бы еще и комментов

evgen5555

Если что-то из базы дергать, то для ноды сейчас почти все вендоры баз пишут драйвера, шоб работало из коробки. Сильно облегчает написание прототипа и изменение модели в будущем.

luna89

ASP.NET
Можно ли использовать из линукса? Насколько просто деплоить в линукс?

Kira


ASP.NET

ты хотел сказать Web API?

Dasar

Можно ли использовать из линукса?
можно
Насколько просто деплоить в линукс?

sudo apt-get install unzip curl
curl -sSL http://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_BRANCH=dev sh && source ~/.dnx/dnvm/dnvm.sh
sudo apt-get install libunwind8 gettext libssl-dev libcurl3-dev zlib1g libicu-dev
dnvm upgrade -r coreclr

http://docs.asp.net/en/latest/getting-started/installing-on-...

0000

Из заявленных плюсов NodeJS - обработка большого количества соединений из коробки, что круто для чатов и онлайн игр.
В России вроде не сильно популярна.
Лично мне NodeJS в продакшене использовать еще не доводилось, пока пишу в стол для себя, что называется.
Исходно NodeJS умеет только поднимать web-сервер, работать с файлами/ошибками + возможности языка, всё остальное (работа с базами/логами/шаблонизаторы/сетевые протоколы/прочее) добавляется через менеджер пакетов.
Express - совсем небольшой фреймворк, который по сути добавляет некую структуру обработчиков адресов (route и Middleware), чтобы как то это дело "стандартизировать" в проекте. Можно и не использовать, или воспользоваться одной из альтернатив.
Большой плюс для старта - отличный видеокурс от Ильи Кантора http://learn.javascript.ru/nodejs-screencast с ложкой дегтя в виде устаревшей версии (но не критично), а также учебник по JS.
Из планируемой засады видится выход следующей версии JS.
До кучки
IBM сделает платформу NodeJS стандартом корпоративной разработки
Из доклада http://www.highload.ru/2015/abstracts/1894.html
В течение последнего года мы разрабатывали проект DMP (Data Management Platform), используя NodeJS для прототипирования. На данный момент проект в большей степени все еще остался на JS и без труда справляется с текущими нагрузками в 10 000 запросов в секунду.
 
В докладе расскажу, почему остановились именно на NodeJS, хотя выбирали между .NET, Go, NodeJS, Python и Ruby. Почему не жалеем о своем выборе и будем дальше использовать для некоторых проектов.

sergeikozyr

Gо:
 
  • Статическая типизация, хоть и немного куцая (nilable типы, прежде всего)
  • Очень жёсткая структура проекта. Не приходится тратить время, как в питоне, на то, как раскидывать файлы, есть, фактически, только один путь
  • Готовая инфраструктура для тестирования
  • Единообразная стандартная либа
  • Компилируемый, достаточно быстрый
  • gofmt, конечно же

Недавно делал проект, состоящий из нескольких частей: программа для устройств, сервис общающийся с этими устройствами, сервис API. Вначале на Go был написан только сервис с устройствами — впечатления были самыми приятными — а API на Python+Flask. И, последнее ощущалось как какой-то вычислительный метод написанный на этом же питоне, т.е. то, что сам язык делает плохо даже на уровне синтаксиса (итерирование по числовыми диапазонам в питоне так себе), не говоря уж об особенностях на уровне исполнения. Ну вот, API после переписал на Go и попа этого стала мягкой и сухой.
Сам язык тоже приятный: сильно спартанский, с одной стороны и забивший на полезные нововведения, вроде алгебраических типов, которые бы закрыли тему NPD, но, в принципе, жить можно, особенно после питона и плюсов. С другой стороны учли весь этот печальный опыт с классами и наследованием и сделали простые интерфейсы, что подталкивает к более тщательному проектированию и очень хорошо сказывается на читабельности сторонних проектов.

yroslavasako

Статическая типизация, хоть и немного куцая (nilable типы, прежде всего)
Очень жёсткая структура проекта. Не приходится тратить время, как в питоне, на то, как раскидывать файлы, есть, фактически, только один путь
Готовая инфраструктура для тестирования
Единообразная стандартная либа
Компилируемый, достаточно быстрый
Всё жутко напоминает яву. Голую.

agent007new

Сам язык тоже приятный:
Я пробовал че-то по мелочи играться, все прикольно кроме ебанутого синтаксиса языка и конструкций, от которых блевать аж тянет. Если бы не это, реально прикольная система получилась бы из го

sergeikozyr

Всё жутко напоминает яву. Голую.
да, но стоит учитывать, что Go — это DSL для написания сервисов, с вытекающим следствием в виде простоты и удобства этого процесса
потом, решает stdlib. В Go он на удивление полон, решает большую часть задач с достаточным качеством. С джавкой могу сравнивать только с 7-ой версией, которую использовал для программирования под андроид и, знаешь, впечатление было не слишком хорошим: нужно было прочесть файл целиком в строку (выводить для логирования) - нет готового метода, цикл, как в плюсах.
Хочется сделать банальный джойн для списка стрингов - хуюшки, пиши цикл. Ничего сложного, но вторая задача довольно частая.

sergeikozyr

все прикольно кроме ебанутого синтаксиса языка и конструкций, от которых блевать аж тянет.
чем?
Вот, скажем, объявление функции:
func name(x int, y int) int {...}

сравним с растом

fn name(x: int, y: int) -> int {...}

Т.е. просто выкинули : и -> как не несущие никакой необходимой функциональности.
Потом, из управляющих конструкций выкинули позорные ( и ), т.к. они обязательно блочные. В тех же плюсах у меня всегда блоки и при этом непонятно зачем скобки.
if a > b {
...

Ну и т.д. Всё нормуль, мне нравится. Синтаксис совершенно не сишный, несмотря на { и }, но это не недостаток, а работа над очевидными ошибками. Попробуй пописать, что-ли, немного, привыкнуть. Я как-то быстро влился и перестал его замечать.

Helga87

func name(x int, y int) int {...}
Сравним лучше с модным Swift:
func name(x: Int, y: Int) -> Int {...}

sergeikozyr

Сравним лучше с модным Swift
в котором типа "иксепшены" в виде магии над алгебраическими типами? Магия — это очень плохо, особенно тогда, когда код без этих иксепшенов ненамного длиннее, если вообще.
ага, и ещё там классические классы с наследованием. Это вообще серьёзно?
Опустим "интерфейсы за минимальное время выражают то, что пытаются сказать классы". Рассмотрим одну важную практическую задачу. Взаимодействие с веб-сервисами. JSON-ы, сериализация, десериализация.
В расте, в котором только интерфейсы, структуру можно пометить как RustcEncodable и RustcDecodable. Компилятор автоматически реализует соответствующие интерфейсы, которые обеспечивают пробегание полей. И после этого структуры можно скармливать всяким JSON/Yaml/whatever сериализаторам и десериализаторам. Где это в swift-е? Фича нужная, почему до сих пор не запилена? Как это сделать для свифтовых классов? Опять магия?

Helga87

Нене, я не пытаюсь сказать, что Swift молодец. Go мне нравится больше.
Просто даже Swift взял объявление функций у Go (ну, и у похожих языков), а не у Java / C.

sergeikozyr

Сорри, люблю побрюзжать, особенно когда есть повод )

agent007new

Сорри, я неправильно выразился: не весь синтаксис кривой, а отдельные конструкции. Пример с функциями, что ты привел - все ок, никаких претензий нет. К сожалению, че-то не могу сходу вспомнить, что меня конкретно раздражало в нем, когда я пытался писать - больше пол года прошло, нужно поковыряться в документации (я щас не беру в рассмотрение такие высокоуровневые идеи как исключения против коды возврата или отсутствие дженериков, хотя в инете пишут, что без второго бывает тяжко). Но вот, например, на днях на хабре была статья. Там вот такая веселая конструкция для вставки элемента в слайс была (при этом, как говорят, без дженериков это даже нормально не завернуть во что-нить приличное):
numbers = append(numbers[:2], append([]int{3}, numbers[2:]...)...)

sergeikozyr

не append, который slice = append(slice, slice2...) ?
upd начал читать, дошёл до "не могу вспомнить", сразу понял, что это про слайс :D
ну да, этот момент самый странный

Helga87

numbers = append(numbers[:2], append([]int{3}, numbers[2:]...)...)
Эта операция имеет линейное время выполнения. На мой взгляд, совершенно правильно, что медленные операции выглядят по-уродски.
Если хочется быстро вставлять в середину списка, разумнее использовать linked list. И вот тут мы наступаем на реальную проблему Go: из-за отсутствия генериков довольно много стандартных структур данных и коллекций в stdlib отсутствуют.

stm5872449

Эта операция имеет линейное время выполнения. На мой взгляд, совершенно правильно, что медленные операции выглядят по-уродски.
Ты умеешь делать вставку по индексу в список за время, меньшее чем линейное? :smirk:

Helga87

Ну, во-первых, у нас уже может быть на руках нужный курсор. Во-вторых, можно иметь дополнительную хеш-таблицу, которая будет выдавать нам указатель на интересующий элемент списка. Можно придумать и более экзотические варианты, все зависит от нашей задачи.

agent007new

Линейное время - это не значит, что нигде не используется. А, во-вторых, не знаю, что там с выделениями памяти в Го - насколько хорошо они работают, но частенько проще двинуть массив, чем память выделить. Следуя подомной логике, нужно вообще запретить компиляцию вложенных циклов - там же вообще квадрат будет, ну или чтобы обойти это ограничение, нужно десять страниц кода написать - чтобы ты точно знал, что хочешь именно квадрата.
Это как когда-то были споры в С++. Что нельзя перегружать операторы, т.к. они скрывают то, что операция может занимать значительное время. А вот, если вместо оператора +, будет функция add, то сразу становится ясно, что это долгая операция.

kill-still

Держи вот, сравнивай, какой из сортов этого самого тебе больше по душе: http://todomvc.com/
Как по мне, имхо лучше не тратить время на изучение всей этой белиберды и ограничиться чем-то легким и действительно полезным типа шаблонизатора на mustache. А когда придёт время и в браузерах запилят ecma6, то и его выкинуть к чертям.

karkar

ну или чтобы обойти это ограничение, нужно десять страниц кода написать
В Go именно так и сделали. Там где в нормальных языках будет одна строчка с filter/map/join, в Go будет 10 строк с императивными циклами.

apl13

Это как когда-то были споры в С++. Что нельзя перегружать операторы, т.к. они скрывают то, что операция может занимать значительное время.
Да-да-да, и если сатана добавит нам еще возможностей, мы должны быть твердыми и не использовать их. :pray: :pop:

schipuchka1

Проблема, что вашу ч0рную магию потом ещё поддерживать как-то.

luna89

У меня в компании пишут код на go, выглядит так:

if err := mw.CropImage(thumb.width, thumb.height, thumb.x, thumb.y); err != nil {
response.Result = false
response.Message = err.Error()
logger.error.Println(err)
return
}
if err := mw.ResizeImage(uint(CONF_CUTTER_THUMBNAIL_SIZE), uint(CONF_CUTTER_THUMBNAIL_SIZE), imagick.FILTER_LANCZOS2, 1.3); err != nil {
response.Result = false
response.Message = err.Error()
logger.error.Println(err)
return
}
if err := mw.WriteImage(destination + DS + "preview.jpg"); err != nil {
response.Result = false
response.Message = err.Error()
logger.error.Println(err)
return
}
var destinationPublic string
if CONF_UPLOAD_TARGET == "s3" {
i := "http://" + CONF_UPLOAD_BUCKET + "." + CONF_UPLOAD_ENDPOINT
destinationPublic = filepath.Dir(strings.Replace(request.Source, i, "", 2))
err = uploadDir(destination, destinationPublic)
} else {
destinationPublic = filepath.Dir(request.Source)
err = saveDir(destination, destinationPublic)
}
if err != nil {
response.Result = false
response.Message = err.Error()
logger.error.Println(err)
} else {
os.RemoveAll(destination)
logger.trace.Printf("Published files in (%s)%s from %s", CONF_UPLOAD_TARGET, destinationPublic, destination)
}

if err != nil {
response.Result = false
response.Message = err.Error()
logger.error.Println(err)
}else {
logger.trace.Println("Ok: ", destination, "=>", filepath.Dir(request.Source))
}

Мне при виде этого кода хочется приделать либо монады, либо исключения, но в go нет ни того, ни другого AFAIK.

Marinavo_0507

Мне при виде этого кода хочется приделать либо монады, либо исключения, но в go нет ни того, ни другого AFAIK.
препроцессор же :)

Helga87

Это не идиоматичный код на Go. Даже если не пытаться угадывать какие высокоуровневые изменения можно сделать, код может выглядеть чуть лучше:

defer func() {
if !response.Result { logger.error.Println(response.Message) }
}()

if err := mw.CropImage(thumb.width, thumb.height, thumb.x, thumb.y); err != nil {
response.Result = false
response.Message = err.Error()
return
}
if err := mw.ResizeImage(uint(CONF_CUTTER_THUMBNAIL_SIZE), uint(CONF_CUTTER_THUMBNAIL_SIZE),
imagick.FILTER_LANCZOS2, 1.3); err != nil {
response.Result = false
response.Message = err.Error()
return
}
if err := mw.WriteImage(destination + DS + "preview.jpg"); err != nil {
response.Result = false
response.Message = err.Error()
return
}
var destinationPublic string
if CONF_UPLOAD_TARGET == "s3" {
i := "http://" + CONF_UPLOAD_BUCKET + "." + CONF_UPLOAD_ENDPOINT
destinationPublic = filepath.Dir(strings.Replace(request.Source, i, "", 2))
} else {
destinationPublic = filepath.Dir(request.Source)
err = saveDir(destination, destinationPublic)
}
if err != nil {
response.Result = false
response.Message = err.Error()
return
}
os.RemoveAll(destination)
logger.trace.Printf("Published files in (%s)%s from %s", CONF_UPLOAD_TARGET, destinationPublic, destination)

Из того, что выглядит лишним, но нельзя убрать без изменения кода вокруг:
1. response должен иметь поле err и не иметь поля Result и Message. Вместо Result проверять err == nil. Message внутри err.
2. выглядит так, что тут требуется функция, которая возвращает err. Запись в response надо делать либо в defer, либо в caller. Тогда будет еще короче:

if err := mw.CropImage(thumb.width, thumb.height, thumb.x, thumb.y); err != nil {
return err
}

Правда, рекомендуется добавлять дополнительную информацию в ошибку, если она обрабатывается не на месте, а переходит на более высокий уровень:

if err := mw.CropImage(thumb.width, thumb.height, thumb.x, thumb.y); err != nil {
return fmt.Errorf("CropImage: %v", err)
}

3. Приведение CONF_CUTTER_THUMBNAIL_SIZE к uint выглядит подозрительным. Если это константы, то они (могут быть) typeless: получают тип в месте использования.
4. Очень подозрительный код по конструированию пути:

destination + DS + "preview.jpg"

Но непонятно, как именно надо менять, т.к. неясно, что такое DS.
5. Названия переменных могут быть короче. В частности, response -> resp, destination -> dest, request -> req.
6. Если есть несколько однотипных операций, примененных подряд, зачастую удобно занести их в массив и запускать их в цикле, но конкретного совета дать тяжело, т.к. кусок кода слишком мал.

luna89

Правда, рекомендуется добавлять дополнительную информацию в ошибку, если она обрабатывается не на месте, а переходит на более высокий уровень:
В проектах над которыми я работал, обычно обработать ошибку на месте было невозможно. Если не работает файловая система или сеть, то надо сразу упасть, но упасть так чтобы ошибка надежно попала в логи и мониторинг для админов.
Тут глядя на код трудно сразу понять, все ли if правильно расставлены, на мой взгяд легко допустить ошибку потому что код зашумленный. В результате одна операция выполнится неуспешно, а остальные продолжат работу, итог - битые данные. Особенно это опасно, потому что сценарий "не удалось записать в файл" никто никогда не тестирует.

Helga87

Тут глядя на код трудно сразу понять, все ли if правильно расставлены, на мой взгяд легко допустить ошибку потому что код зашумленный.
Я согласен с оценкой, что код зашумленный (см мое предыдущее сообщение), но в этом вина не языка.

luna89

Я согласен с оценкой, что код зашумленный (см мое предыдущее сообщение), но в этом вина не языка.
В твоей версии вот это блок три раза повторяется:

response.Result = false
response.Message = err.Error()
return

Helga87

Да, но только потому, что мне не хватило контекста для правильного изменения кода.
Если запостишь кусок подлиннее, я смогу сделать код значительно чище.

apl13

"Как-то" все равно не получится, и количество возможностей тут роли не играет.
Оставить комментарий
Имя или ник:
Комментарий: