Дмитpий Hecтepук

Блог о программировании — C#, F#, C++, архитектура, и многое другое

Archive for the ‘Technology’ Category

Работа лето интерн C++ программист студент графика :)

6 комментариев

Вообщем, тут такое дело. У меня есть система кинетической типографики в достаточно зачаточном состоянии, и я подумал что может кто-нибудь с начинающими скилами С++ захочет покодить ее за деньги в летние месяцы этого года. И денежку получить и опыт какой-никакой.

Система моя называется Kinetica, она написана на C++ с использованием Direct2D/DirectWrite и FFMPEG. По сути, это программа, которая просто генерит анимированный текст (в видеофайлах), и мне нужен кто-то, кто

  • Поанализирует мои запросы на разные механизмы анимации

  • Напишет код который эту анимацию сделает (хочется красивое API)

  • Напишет какие-нибудь тесты для всего этого

Я могу по мере возможности помогать разбираться с кодом, но основная моя функция — писать в трекер список задач. А ваша — их реализовывать.

Касательно навыков, от вас требуется

  • Знание С++ и как на нем делать приличное ООП

  • Навыки работы с Visual Studio

  • Некоторое понимание компьютерной графики

  • Умение работать с Git (я использую GitLab)

  • Умение работать с баг трекером

Вообщем если вы студент, учили С++ и думаете «а зачем мне оно надо», то тут есть шанс погенерить интересные видео, поднять скилы, и все такое. Работа фултайм, задач будет много — как на создание красивого API, так и на создания на этом API нужных мне анимаций. Которых будет много.

Деньги — самое главное. $1k/месяц пейпалом. Работа, как вы поняли, удаленная.

Вопросы, пожелания, пишите, отвечу что да как.

Реклама

Written by Dmitri

16 марта 2017 at 1:10

Опубликовано в Technology

К вопросу о front-end’ах

4 комментария

Да, я обещал написать про front-end’ы, так что вот. Для начала расскажу что это такое. Если коротко — можно писать код как plain text, а можно его писать с помощью редактора a la Microsoft Equation Editor. Именно это делает Mathematica, и получается неплохо.

Но мы начнем с простого, например с того факта что * не умножение а звездочка и было бы логичнее использовать \times или хотя бы \cdot. Я понимаю что кого-то нервирует что произведение x и y будет выглядеть как x×y, но это пожалуй единственный кейс который приходит в голову, и тут можно написать x \cdot y и все довольны.

Вы заметили что я начал использовать \LaTeX? Его Дональд Кнут изобрел чтобы математику верстать. Выглядит сугубо приличнее чем plain text Вот например хочу я, допустим, деление: конечно x/y выглядит более менее сносно, но \frac{x}{y} как-то солиднее. Или foo->bar() все же не так круто как \text{foo}\to\ bar().

Вообще идентификаторы символов тоже хочется иметь погибче, например почему я не могу назвать меременную C^1_k или же например \widetilde{abc}?

Все те условности к которым мы привыкли навязаны plain text представлением. И если отойти от него – да, нужно иметь специальные форматы файлов, но структурированный как дерево код легче обходить, так что плюшки тут очевидны. Это как раз то, что делает MPS, но можно сделать ещё круче.

Вообщем такие вот мысли…

Written by Dmitri

18 июля 2016 at 0:33

Опубликовано в Technology

Заметки про Rust

4 комментария

Содержание

Я не знаю как с экономической точки зрения в России можно не работать треть месяца, но ладно — для многих водка решает, а тех кому нечем заняться ждет обзор языка Rust с точки зрения человека который пишет в основном на C++/C# (хотя я теперь модный и знаю сколько-то Kotlin’а, что тоже полезно, т.к. Java трогать ну совсем не хочется).

Так вот, давайте по порядку и с заголовками, чтобы красиво было. (Да, подсветка синтаксиса тут во F#-у, т.к. wordpress.com пока не разродился на Rust.)

Примитивные типы

Начнем с целочисленных типов: тут все хорошо и стандартизированно: вместо всяких unsigned long long которые в тех же плюсах вообще непонятно что значат, в Rust тип u8 значит ‘unsigned и 8 битов’ что очень понятно, в принципе, ну и по аналогии i32 это 32-битный int.

Есть также usize/isize – это биты размера системы, то есть если вы на 64-бит (я надеюсь), и что хорошо, так это то что в отличии от C++, где есть весьма существенные непонятки с типом size_t, а также языками C++/C#/Java, где индекс массива может быть signed, в Rust-е индекс массива это строго usize. Это же здорово!

Да, насчет чисел с плавающей точкой — тут f32/f64, все просто.

Операторы

Все как в С-образных языках, но жестко выпилены операторы ++/--, а логические операторы можно применять только к булевым переменным и, наоборот, побитовые – только к целочисленным (то есть к f32/64 не получится). Это хорошо т.к. снижает кол-во возможных непоняток.

Переменные

Объявление переменной в Rust несложно, например:

let mut a:i32 = 2+3*4;

Тип, как видите, идет после названия. В примере выше он не нужен т.к. type inference в Rust очень умен и умеет делать вывод на этапе вызова (я позже покажу какого это).

Переменные в Rust — хитрые твари потому что:

  • Примитивы выделаются на стэке если только ты их вручную не задвинешь в кучу через Box<>
  • By default немутабельны, но могут быть сделаны таковыми с помощью ключевого слова mut
  • Владеют той памятью на которую ссылаются. Об этом позже т.к. идея сложная

Помимо локальных есть еще глобальные переменные:

  • Константы которые просто инлайнятся и сами адреса не имеют
    const MEANING_OF_LIFE:u8 = 42;
    
  • Статические переменные, которые можно даже делать мутабельными, но если ты так сделал – то придется ващевеськод оборачивать в unsafe т.к. система не может мониторить что ты правильно работаешь с глобальной переменной, в которую вообще все могут писать
    static mut Z:i32 = 123;
    

И да, язык хочет чтобы глобальные переменные были константами. И вообще, code style inspections встроены в сам компилятор что, имхо, дурной тон и так вообще не надо делать.

Control flow

If

Тут много интересного. Во-первых, нет тернарного оператора ?: — всесто этого if возвращает значение:

let day = if temp > 20 {"sunny"} else {"cloudy"};

Где return, спросите вы? А вот… в старой доброй традиции терминального ввода, MATLAB’а и прочих, правило Rust такое – если после чего-то нет точки с запятой ;, то это – return value. По мне так достаточно косячно т.к. ну очень плохо читается. Вариант использовать return тоже есть, конечно, но уверен что растаманы будут ругаться.

Да, эти if-ы всегда требуют фигурные скобки вокруг блоков, но зато не требуют круглых скобок вокруг проверки условия.

While/loop

Что касается while, то тут все то же самое, continue и break работают. А вот do-while не сделали, зато сделали loop который чем-то аналогичен while(true) или for(;;). И это в языке который печется о безопасности.

For

Цикл for работает как-то вот так:

for x in 1..11 
{
  // skip 3
  if (x == 3) { continue; }
  // stop at 7
  if (x == 8) { break; }
  println!("x = {}", x);
}

Как вы догадались, 1..11 это range, то есть набор чисел от 1 до 10 включительно. Такой вот «обходной» подход к for сравним с обычным IEnumerable, то есть ничего особенного, просто очередная редукция энтропии. Кстати, 11..1 не получится и приведет к косякам, ну и шаг хождения (как 1:101:2 в MATLAB) тоже указать нельзя.

А да, и если нужен индекс итерируемого элемента, есть специальный метод который вернет вам не просто элемент, а кортеж индекс-элемент:

for (pos,y) in (30..41).enumerate()
{
  println!("{}: {}", pos, y);
}

Match

Теперь насчет switch — его нет, есть match, и он раз в 100 мощнее. Ну вот например он умеет обрабатывать range’ы:

let country_code = 999;
let country = match country_code 
{
  44 => "UK",
  46 => "Sweden",
  7 => "Russia",
  1...1000 => "unknown",
  _ => "invalid" // try commenting this out - must cover all cases!
};

И да, он тоже, как и if возвращает значение, которое можно присвоить. Только вот тут есть один косяк… приглядитесь! Видете диапазон 1...1000? Там три точки. А ранее было две! И ранее 1..11 означало от 1 до 10 включительно, а тут — от 1 до 1000 включительно. Такой вот когнитивный диссонанс. И причем авторы языка это специально сделали, «чтобы люди не путались». Ну-ну.

Структуры данных

Массивы

Начнем с массивов. Ну вот как-то так:

let mut a/*:[i32;5]*/ = [1,2,3,4,5];

Тип массива я, опять же, закомментил — вывод типов и тут работает на ура. Массив на стэке. Можно менять по индексу, при неправильном индексе получим панику. Есть метод len() для длины, т.е. ходить по массиву можно так:

let b = [1u16; 10];
for i in 0..b.len()
{
  println!("{}", b[i]);
}

Не знаю как вам, а мне форма записи 0..b.len() как-то не очень. Зато синтаксис выше — [1u16; 10] — это для заполнения десяти элементов массива одним и тем же значением. Удобно.

Многомерные массивы тоже реальны как массивы массивов:

let mtx:[[f32; 3]; 2] = 
[
  [1.0, 0.0, 0.0],
  [0.0, 2.0, 0.0]
];
println!("{:?}", mtx);

Слайсы

Слайсы – это как бы ссылки на куски массива, т.е. диапазоны памяти. То есть, если у нас есть массив, можно его кусок одолжить и че-то с ним поделать:

fn use_slice(slice: &mut [i32])
{
  println!("first elem is {}, len = {}", slice[0], slice.len());
  slice[0] = 4321;
  // will crash
  //let z = slice[10];
}
fn slices()
{
  // a slice is part of an array
  // its size is not known at compile time
  let mut data = [1,2,3,4,5];
  
  // start w/o mut, borrow as a slice
  use_slice(&mut data[1..4]);
  use_slice(&mut data); // entire array
  println!("data after slice use = {:?}", data);
}

В отличии от массивов, слайсы могут быть хз какого размера.

Вектора

Вектор — дженерик тип Vec — это динамический массив, причем в куче. Можно добавлять и удалять данные.

let mut a = Vec::new();
a.push(123);
println!("a = {:?}", a);
let idx:usize = 0;
println!("a[0] = {}", a[idx]);

Из кода выше должен возникнуть резонный вопрос: где название типа данных? Почему мы можем вообще вызывать Vec::new() если нигде нет аннотаций типа? Ответ на этот вопрос – очень умный вывод типов Rust’а.

Да, поскольку в Rust есть Option<T>, доступ к элементам безопасен и может быть сделан вот так:

match a.get(5)
{
  Some(x) => println!("a[5] = {}", x),
  None => println!("error, no such element")
}

Но не бойтесь, так писать везде где нужен элемент не придется.

Да, насчет итерации вектора, тут все просто:

for x in &a { println!("{}", x); }

Вот этот амперсанд & перед названием ветора перед операции означает «одолжить». То есть на момент итерации, вектор «одолжен». Да, и варианта менять вектор во время итерации тут нет, спасибо Rust’у с его безопасностью.

Что еще? Вектор ведет себя как стэк (т.е. имеет push/pop методы). Вот если нужно например его опустошить в обратном порядке, можно так:

while let Some(x) = a.pop()
{
  println!("{}", x);
}

Выше — немного магии. Как это у нас в while внезапно не true/false а Option<T>. А вооот! Rust поддерживает if let/while let, которые проверяют на None/Some<T>. Очень удобно!

Строки

Тут все хорошо и плохо одновременно. Хорошо потому что Rust гарантирует что строки это всегда валидные UTF-8 последовательности, а плохо потому что есть два типа строк — String и &str.

Начнем с &str — это т.н. ‘string slice’, но не в классическом смысле: слайс строки как Vec<u8> крайне бессмысленнен т.к. это байты Юникодной последовательности, а &str – это особный тип, который дает доступ к строке, которую можно разбить на последовательность буков и делать с ними что-то:

let s:&'static str = "hi there!";
// s = "bar"; // cannot reassign immutable
//let a = s[0]; // cannot index
  
for c in s.chars().rev() // reversed! also as_bytes()
{
  println!("{}", c);
}

В примере выше, мы статически аллоцируем текст и берем его как &str а дальше с помошью chars() разбираем на буквы и делаем что хотим.

А теперь про String — вот этот тип как раз для того чтобы менять, т.е. это мутабельный Vec<u8> в который можно аппендить и вообще:

let mut letters = String::new();
let mut a = 'a' as u8;
while a <= ('z' as u8)
{
  letters.push(a as char);
  letters.push_str(","); // note the _str
  a = a+1;
}
println!("{}", letters);

Вообщем, со строковыми типами в Rust много чехорды, люди пишут умные блог-посты на эту тему, и толком непонятно что юзать – зависит, конечно, от того будете ли вы вашу строчку «шарить».

Option<T>

Это специальная структура данных (аналог boost::optional или F#‘ному Option<'t>) которая является перечислением, и имеет два возможных значения

  • None — значит «данных нет» и тут нечего ловить.
  • Some(T) где T — это то значение что вернули.

Ну вот представьте, вы захотели поделить одно число на другое, но на ноль делить нельзя (математика, 1 класс общеобразовательной школы), поэтому вы пишете что-то вроде:

let x = 3.0;
let y = 0.0;
let result:Option<f64> =
  if y != 0.0 { Some(x/y) } else { None };
match result {
  Some(z) => println!("{}/{}={}", x, y, z),
  None => println!("cannot divide {} by {}", x, y)
}

Ну и опять же, растаманская магия дает сразу выписать результат, если он есть, вот так:

if let Some(z) = result { println!("result = {}", z); }

Кортежи

Не, ну а как же без них? Хотите вернуть из функции и сумму и произведение двух чисел? Пожалуста:

fn sum_and_product(x:i32, y:i32) -> (i32, i32)
{
  (x+y, x*y)
}

Теперь можно их выписать например вот так:

let x = 3;
let y = 4;
let sp = sum_and_product(3, 4);  
println!("sp = {:?}", sp);
println!("{0} + {1} = {2}, {0} * {1} = {3}", 
  x, y, sp.0, sp.1);

Не нравится индексиция через точку? Вы еще С++ не видели. Ну ладно, ладно, давайте тогда деструктурируем:

let (a, b) = sp;
println!("a = {}, b = {}", a, b);

Кортежи-кортежей тоже в принципе реально, но написать foo.1.2 вам никто не даст:

let sp2 = sum_and_product(4,7);
let combined = (sp, sp2);
println!("last element is {}", (combined.1).1); 

Зато деструктуризация кортежа-кортежей выглядит красиво:

let ((c,d),(e,f)) = combined;

Что еще: а, да, кортеж это ж где разные типы можно хранить. Вот, пожалуйста. И да, одноэлементные кортежи немного кривовато делаются:

let foo = (true, 42.0, -1i8);
let meanings = (42,);

Структуры

Старый добрый сишный struct, никакого буллшита:

struct Point
{
  x: f64,
  y: f64
}
struct Line
{
  start: Point,
  end: Point
}

Методы в его тело не добавляются, а конструкторов-деструкторов как таковых нет как феномен, инициализация идет как-то вот так:

let p = Point { x: 3.0, y: 4.0 };
println!("point p is at ({},{})", p.x, p.y);
let p2 = Point { x: 5.0, y: 10.0 };
let myline = Line { start: p, end: p2 };

Для страктов, как и для кортежей (и всего остального) тоже работает деструктуризация. Как это выглядит мы увидим когда посмотрим на…

Перечисления (enum-ы)

Старый добрый… а, что, не такой? А, ну да. Enum в понимании Rust – это совокупность просто лейблов, кортежей и struct’ов, типа используйте что хотите (и да, generic enums тоже возможны, смотрите на Option). Вот например как можно описать цвет:

enum Color
{
  Red,
  Green,
  Blue,
  RgbColor(u8,u8,u8),
  CmykColor{cyan:u8,magenta:u8,yellow:u8,black:u8},
}

Ну а для разбора такого счастья можно использовать всю мощь pattern-matching’а:

let c = Color::CmykColor{cyan: 0, magenta: 128, 
  yellow: 0, black: 255};
match c
{
  Color::Red => println!("r"),
  Color::Green => println!("g"),
  Color::Blue => println!("b"),
  Color::RgbColor(0,0,0) 
  | Color::CmykColor{black:255,..} 
    => println!("black"),
  Color::RgbColor(r,g,b) => println!("rgb({},{},{}", r, g, b),
  _ => ()
}

Заметили .. выше? Это не range, конечно, это описание того что «пофиг чему равны другие поля».

Функции

Тут все, вообщем-то, просто:

Просто функции

Функция начинается с fn, далее берет один или несколько аргументов (тип, как всегда, после имени):

fn print_value(x:i32)
{
  println!("value = {}", x);
}

Функции могут также возвращать значения: тип возврата пишется через стрелочку:

fn product(x: i32, y: i32) -> i32 // return value
{
  let z = x * y;
  z // no semicolons
}

Возврат, как уже говорил, идет того значения, у которого нет ;.

Аргумент можно передать «по ссылке» – для этого используется & как на типе аргумента так и в функции, а для «дереференса» ссылки используется *. То есть поведение совсем уж в разрез с С++.

fn increase(x: &mut i32) // start with i32
{
  *x += 1;
}
let mut z = 1;
increase(&mut z); // lend z

Методы

Помните я сказал, что у struct’ов как таковых нету собственных функций? Но их можно добавить! Делается это вот так:

struct Point
{
  x: f64,
  y: f64
}
struct Line
{
  start: Point,
  end: Point
}
impl Line
{
  fn len(&self) -> f64
  {
    let dx = self.start.x - self.end.x;
    let dy = self.start.y - self.end.y;
    (dx*dx+dy*dy).sqrt()
  }
}

Ключевое слово impl позволяет определить реализацию того или иного метода для структуры. Заметьте как, выше, функция sqrt() вызывается на типе f64! Хотя я конечно же мог бы вызвать ее как f64::sqrt(), тут как кому удобнее.

Замыкания

Ну вот есть у вас функция:

fn say_hello() { println!("hello"); }

Вы можете взять и сделать из нее переменную. И потом вызвать ее как функцию:

let sh = say_hello;
sh();

Это никого не должно удивлять. Как и вариант создания таких переменных прямо в месте где хочется их использовать. Тут у нас Ruby синтаксис! Серьезно, вот:

let plus_one = |x:i32| -> i32 { x + 1 };
let a = 6;
println!("{} + 1 = {}", a, plus_one(a));

То есть plus_one это вполне себе функция. Сразу вопрос: а что с захватом окружения? А вот тут включается весь злой арсенал проверок Rust: если что-то из окружения захвачено, мы не отпустим пока сама лямбдочка не будет удалена. Как? А вот так:

let mut two = 2;
{
  let plus_two = |x|
  {
    let mut z = x;
    z += two;
    z
  };
  println!("{} + 2 = {}", 3, plus_two(3));
}
let borrow_two = &mut two;

Выше — искусственно сделанный scope, который гарантирует что plus_two будет удалена и, тем самым, «отпустит» two, которую она захватила.

Вот как-то так: передали контроль над переменной: все, пиши пропало. Поэтому лучше одалживать.

Время жизни

Раст жестко контролирует правильность использования переменных. По сути, на всех переменных навешан индивидуальный ReaderWriterLock, т.е. читателей может быть сколько угодно, а вот менять переменную может только один.

Владение

Каждая переменная «владеет» контентом, но поведение отличается в зависимости от того, на стэке она или в куче. Вот если она в стеке, например

let v = vec![3,2,1];

то это значит что такое вот невинное, казалось бы, присваивание как

let v2 = v;

означает фактически, что v2 забирает управление памятью, и что отныне переменную v использовать нельзя, т.к. у нее «забрали» управление. Это значит что вот это не скомпилируется:

println!("{:?}", v);

То же самое происходит если лямбду написать как

let foo = |v:Vec<i32>| ();
foo(v);

Поскольку функция foo забрала вектор, использовать его пока лямбда в scope — нельзя.

Это поведение на языке C++ называется move semantics, т.е. объект как бы «перемещается», а старая его копия больше не валидна. Работает это, правда, только для тех типов которые не определили трейт Copy (о трейтах позже). Для примитивов работает этот трейт, и у нас копирование вместо move’а:

let u = 1;
let u2 = u;
println!("u = {}", u); // компилится без проблем!

Как вернуть управление из функции? Ну, можно вот так:

let print_vector = |x:Vec<i32>| -> Vec<i32>
{
  println!("{:?}", x);
  x
};

Но это гемор, поэтому Rust вводит такое понятие как…

Одалживание (borrowing)

Итак, мы с вами договорились до того, что в любой момент только одна переменная «владеет» доступом к данным, а все другие — в пролёте. В терминах C++, можно сказать, что передача такого параметра — это передача unique_ptr.

Что делать если хочется просто поработать над объектом (т.е. shared_ptr)? Тогда можно передать ссылке на него, и эта ссылка означает «одалживание» (borrowing) объекта:

let print_vector = |x:&Vec<i32>| // take a reference
{
  println!("x[0] = {}", x[0]);
};
let v = vec![3,2,1];
print_vector(&v);
println!("v[0] = {}", v[0]);

Также эту ссылку можно сделать, в принципе, мутабельной и менять объект.

Lifetime

Вы не видите lifetime’ов точно так же, как на выводе типов вы не пишете вручную аннотаций. А они есть. Например, типичная функция выглядит вот так:

fn bar<'a>(x: &'a mut i32) -> &mut i32 // lifetime elision
{
  x
}

Вот это вот <'a> может показаться type parameter’ом из F#, но нееет, это время жизни, и оно подчиняется разным хитрым правилом. Есть время жизни 'static, которое обозначает жизнь программы. Другие определения — это на ваше усмотрение.

Про lifetime’ы можно написать отдельный пост (или несколько). Это очень крутая штука, но она вирусная (как GPL) и способна просочиться через весь ваш код.

Всякая всячина

Крейты (ящики)

Rust поставляется с хитрой системой сродни NuGet’у. Проектным файлом служит файл в формате TOML, который описывает не только то, что мы строим (не беспокойтесь, файлы руками описывать не нужно), а также зависимости которые взяты из репозитария crates.io или откуда-то ещё.

Соответственно, помимо компилятора, есть еще crate.exe, который может как собрать ваш проект, так и запустить его или, например протестировать.

Модули

В Rust все делится на модули (ключевое слово mod) которые можно либо держать в одном файле либо распихать по файлам и папкам. Вот например тут

pub mod greetings
{
  pub mod english;
  pub mod french
  {
    pub fn hello() -> String { return "bonjour".to_string(); }
    pub fn goodbye() -> String { return "au revoir".to_string(); }
  }
}

описан файл lib.rs (значит будет собрана DLLка), и хоть модуль french включен прямо тут, модуль english лежит в файле greeting/english.rs. Convention over configuration, однако!

Ключевое слово pub определяет, что видно наружу, а что нет. Импортируется и ипользуется это очень просто:

extern crate phrases;
use phrases::greetings::french;
fn main() {
    println!("English: {}, {}", 
      phrases::greetings::english::hello(), 
      phrases::greetings::english::goodbye()
    );
    println!("French: {}, {}", 
      french::hello(), 
      french::goodbye()
    );
}

Ключевое слово use — что-то вроде using namespace в C++.

Да, забыл сказать — пакеты компилируются на стороне пользователя, т.е. поставляются как сорцы. Упс!

Тестирование

Как и язык D, Rust просто влепил тестирование прямо в суть языка на уровне набора атрибутов. Вот например

#[cfg(test)]
mod tests
{
  extern crate phrases;
  #[test]
  #[should_panic]
  #[ignore]
  fn english_greeting_correct()
  {
    assert_eq!("helloo", phrases::greetings::english::hello());
  }
}

Делает конфигурацию test, добавляет тест который ожидает падения, ну а дальше все как и в других языках. Запускается это дело с помощью cargo test. Как и в D, это очень удобно, не надо качать сторонние фреймворки.

Документация

Специальные комментарии /// для кусков кода и //! для всего модуля целиком дают rustc.exe сгенерить красивую документацию по вашему коду. Highly recommended!

Заключение

Я тут постарался как-то описать Rust по сравнению с C#/C++. Не могу сказать что хочется вот прямо взять и начать на нем писать, но некоторые умные идеи я из него почерпнул. ■

Written by Dmitri

4 января 2016 at 23:02

Опубликовано в Technology

Tagged with

Отсутствие итогов 2015 года

5 комментариев

Это уже стало вроде традицией каждый год писать блог-пост по окончанию года, только вот незадача — каждый год получается все как-то тупо и еще тупее, прям до боли. Но я все-таки попробую.

Прежде всего, причина по которой руки поднялись что-то писать, что в плане успешности год был офигенный. О-фи-ген-ный! Я имею ввиду с финансовой точки зрения, т.к. рассказывать про то как я написал ПО, которое изменило человечество, я не могу. Я уже давно пишу исключительно для себя, и боюсь в этом плане чего-то интересного я не подкину. При этом у меня все еще возникают интересные идеи в плане ПО, которыми я иногда делюсь.

Примерно на этом этапе я мог бы позлорадствовать про доллар за 74 и евро за 80, но скажу лишь, что когда на рынке идет боковичок и деньги в буквальном смысле раздают, надо брать. Тут и боты толком не нужны, берем механическую клаву, скальперский привод (или на коленке писаный самопал) и начинаем клацать.

Насчет гаджетов всяких и программулек. Ну что тут сказать? Я записал сколько-то видосов для SpbDotNet (.NET сообщества в Питере) на Sony α7Rii, это лучший фотоаппарат на сегодняшний день и еще долго таким будет. И вообще я много на него уже пофоткал и очень доволен, хотя нет предела совершенству.

Насчет языков программирования — на D в уходящем году выло написано ровно ничего. На F# — только фиксы в MathSharp по требованиям пользователей. Покупки прог в этом году шли прятным бонусом, Брайан Даунинг даже сделал обзор X2C у себя в видео, заодно простимулировал меня пофиксить несколько проблем с разным легаси вроде Excel функций про которые я вообще не знал.

В технологическом плане в ушедшем году интересного было очень мало. Вышел iPad Pro который я не купил (но собираюсь), так что я периодически покупал книги по финмату и ножи. Да, я люблю ножи.

Да, все-таки удалось попробовать Rust, но выводов пока нет. Я тяготею к тому что приносит деньги, так что мне сильно отъезжать от канонов негоже. К тому же, С++ радует, я посетил ряд конференций — это C++ Russia, ACCU, CppCon, Meeting C++ и на двух последних даже сделал доклады. Ну были и другие конфы, всего по мелочи.

Что ещё? Блин, все-таки хочется влиться в финмат тусовку по полной, но мы уже вошли в какую-то зону апатии, когда мы на поезде с которого уже не сойти, а последняя остановка называется retirement, причем не в смысле «пенсий» — у меня ее нет, и у вас скорее всего тоже — а скорее в смысле «лежать на пляже на канарах». Канары хорошие, да, годное место.

Чё-то как-то сумбурно получилось, и даже удивительно что вы дочитали досюда. Наверное в новом году нужно делать какой-то reboot и начать писать про финмат, правильное использование статистики, и прочее добро. Только дойдут ли у меня руки? Вот не уверен.

Вообщем… всех с новым 2016! Не знаю как вам, а мне кажется что все будет просто супер!

Written by Dmitri

31 декабря 2015 at 23:59

Опубликовано в Life, Technology

Tagged with

Еще немного про ботов которые будут на DotNext

leave a comment »

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

Так вот, о чем это я? Да, боты вообщем. Я на конфе расскажу как все это дело пишется, сейчас же хочу обсудить некоторые сценарии того, зачем собственно все это надо. Не все, конечно сценарии, но некую выборку. Итак, полетели!

Книги и прочая утварь

В 2008м году, Wiley (они публикуют, в том числе, много финансовых книг под лейблом Wiley Finance) подало в суд на некого Таиландца который посмел, скотина, продавать не-американские издания книг американцам. Wiley суд, к счастью, продули (но очень боролись!), а нам же предстоит разобраться в том, откуда ноги растут у этой проблемы.

Вы наверное знаете, что в США и в Европе цены на многие вещи, скажем так, отличаются. В большинстве случаев, если брать электронику, то она дешевле в США, чем лично я пользуюсь, т.к. периодически летаю на всякие конфы. В свое время, книги тоже были сильно дешевле в США чем в Европе, и еще, в отличии от других товаров, не подпадали под налоги (НДС, который может быть под 20%, плюс налог на импорт).

Но я вас удивлю, паблишеры — жадные сцуки. Точнее у них те же проблемы что и у record labels: народ все пиратит нещадно, таких наивных как я, которые любят «читать мертвое дерево» уже мало. В результате, паблишеры озверели, что привело к следующему:

  • Книги в США стали дороже чем в Европе.
  • Паблишеры начали делать разные «редакции» книг для США и International, помечая их большими красными лейблами «not for sale in the United States».
  • Умные поцики поняли что это целый рынок и начали перепродавать не-US книги в Штатах. Согласно first-sale доктрине, их деятельность признана полностью законной.

Паблишеры в свою очередь звереют в разных направлениях. Например, они публикуют книги в твердом переплете, делая их безумно дорогими для обычных читателей — сделано это специально, так чтобы книги покупали только библиотеки у которых, считается, «резиновый» бюджет. Ну а что касается журналов, то есть реально подоночные компании вроде Elzevier которые взвинчивают на них цены и продают не индивидуально а наборами по несколько штук, что порой приводит к бойкотам и прочей нечести.

Так вот, о чем это я? Ах да, есть такой феномен, что периодически некоторые книги сильно падают в цене. Раза в 2-3. Причем это очень сложно уловить. Например, если взять книгу Glasserman’а по методам монте-карло, то вы увидите что ее цена в твердом переплете (GBP35) меньше чем в мягком (GBP47). Почему такой перекос? И почему я, в свое время, смог купить ее где-то за GBP20?

Ответ на это простой: там боты. Цены на книги на Амазоне и не только выставляются динамически. Причем боты иногда перегибают палку, выставляя на книгу цену в USD23 миллиона например. Боты которые выставляют цены мы не можем контролировать, но мы можем их мониторить и, по возможности, находить возможности не только для удобного приобретения но и для перепродажи.

Вектора тут два:

  • Цена на книгу низкая сама по себе относительно исторических значений. Берем на Amazon сразу пятак, продаем на Abebooks, Ebay или где-то еще.
  • Цена на книгу существенно отличается от цены в другой стране. Тут тоже можно поарбитражить.

Конечно, вместо книг можно подставить любой другой товар, но книги — хороший пример, т.к. их ценообазование очень шаткое. С другой стороны, книги многие пиратят, и возможно вот конкретно вам бумажные книги уже некомильфо. Но я как-то пока предпочитаю бумагу.

Самолеты и прочие средства передвижения

Ценообразование полетов – та еще песня. Мы знаем что там как-то все сезонно, плюс зависит от пипла который уже набился на ваш самолет, но строго говоря — все очень мутно, и боты эту мутность разруливают.

Работает это примерно так: вы допустим стали биологическим рабом, нарожали потомства и теперь не можете вообще выехать за иключением школьных каникул. Ну, хотя бы даты известны. Задаете даты, бюджет (ориентировочно), и сколько вы готовы лететь/куковать в аэропорту на пересадке. А дальше бот периодически (но не очень часто т.к. API платный) делает поиск и возвращает вам возможные результаты, оптимизируя по вашим показателям вроде «я никогда не полечу на RyanAir».

Дальше — интереснее. Если вы (не дай сотона) часто летаете, у вас наверняка накопилась куча «поинтов» которыми можно расплатиться вместо того чтобы тратить реальные физ.деньги. Боты – единственный способ понять, сколько ваш полет будет стоить именнов этих поинтах. Не будем забывать, что поинты можно докупать, так что возможности для оптимизации достаточно обширны.

А далее, можно добавить факт сопряженности поинтов от авиалиний и некоторых кредитных карт, варианты апгрейда до бизнеса, варианты с отелями и прочие плюшки. Креативить можно бесконечно, только подумайте, имеет ли оно смысл?

Мероприятия в разрезе времени

Я часто где-то бываю, и обычно помимо «официальных» эвентов мне в перерывах нечем заняться. С другой стороны, есть прекрасные сайты вроде Meetup.com которые агрегируют разные встречи географически. И это уже здорово, т.к. Meetup можно мониторить и приходить на то что нравится — например, из последнего, я сделал доклад на Chicago C++ User Group пока был в Чикаго — только это правда не я нашел эвент, мои боты натренерованы на другого сорта эвенты.

Тут есть один нюанс: Meetup в какой-то момент ссучился и теперь не дает вступать в географически разные группы. Что как бы проблема если хочется общаться и региться на мероприятие. И тут… ну да, тут опять помогают боты чтобы зарегить себе 100500 разных аккаунтов (примечательно что и сам саппорт Meetup предлагает так делать) и потом гулять по сайту уже этими аккаунтами. Неудобно, да, но лучше так чем никак.

Еще более интересная задача — это event planning в разрезе. Откуда я знаю, что где и когда, и когда надо подавать заявки? В принципе тут можно сильно накосячить, а можно наоборот сфомировать очень эффективную поездку. Я не скажу что боты тут суперполезны (разве что попарсить RFP на Lanyard, хотя там и RSS есть), но им тоже можно найти применение. Но скорее всего, в этом случае, система – это большая такая записная книжка, см. например мой календарь.

Заключение

Вообщем, я тут немного прошелся по некоторым юз-кейсам, но не упомянул другие не менее интересные варианты. (например, создание чат-бота для сервиса анонимного чата дабы найти себе S.O.). Надо же что-то оставить на доклад (который будет тут). До встречи на конфе! ■

Written by Dmitri

17 ноября 2015 at 16:41

Опубликовано в Technology

Итоги 2014

2 комментария

personal efficacy treeСловами не передать какое нужно нынче количество усилий чтобы вот так взять и написать блог-пост. Вот сижу тут под новый год, а меня все постоянно отвлекают: например, человек только что прислал вот такую фотку (вам не покажу ибо бред). Мне кажется полное забрасывание информацией – это стало уже комильфо, в то время как мы должны, по идее, от людей которые нам что-то постоянно кидают, ну если не отстреливаться ружьем то хотя бы делать /alertsoff. Также, если вдруг вы еще помните черную магию batch-файлов, можно тупо настрочить

taskkill /f /im skype.exe
taskkill /f /im chrome.exe

И это уже закроет 99% информационного шума. Все, кажется можно начинать.

.NEXT

Вообще, .NET конференция – это была моя давняя мечта. А в этом году их было аж две: в апреле в СПб на 300 человек, и в Москве совсем недавно на 400. На обеих конфах top-3 места по докладам взяли сотрудники JetBrains, и если на первой конфе нас было очень много, то на второй – там уровень докладчиков был еще выше и соответственно конкуренция была серьезная.

Я в Top-3 не попал, зато попали

  1. Роман Белов: Memory & Performance. Tips & Tricks
  2. Дмитрий Иванов: Принципы построения многопоточных десктопных .NET-приложений на примере ReSharper
  3. Дино Эспозито: ASP.NET vNext: What it means to you and what it means to Microsoft

Дино был нашим keynote speaker на конференции, и в целом слушателям он понравился. Думаю и на будущие конференции его можно звать, хотя естественно хочется «повышать градусность» и звать других известных спикеров тоже. Получится это или нет – покажет время.

Пока план .NEXT – повторять то, что уже работает (2 эвента в год, один в СПб, другой в Мск). Я бы конечно хотел сделать что-нибудь за пределами: буду думать про Хельсинки, хотя опыта организации международной конфы у меня пока нет. И самое главное, совершенно непонятны финансовые риски и возможные доходы.

nesteruk_alt_enter

Технологии

Что могу сказать? Я вам не Thoughworks Technology Radar, у меня спектр применения всякого технологического счастья очень узкий.

Тем не менее, в плане .NET развитие очень интересное: много чего ушло в open-source и есть подозрение что вообще весь .NET станет cross-platform т.к. иначе никто на нем писать не будет. Ведь популярность всяких там Node и иже с ним никуда не делась: все хотят все гнать на Linux и точка. Я конечно этому очень рад т.к. для меня ASP.NET MVC это идеальный тул, хотя сейчас набегут рубисты и скажут что «все это уже было». Ну ок.

Помимо развития .NET, продолжается прогресс в степях С++: в этом году я пару раз выступал на встречах C++ User Group Russia, а в следующем году будет конференция (программа, как видите, формируется) и я буду там делать доклад и еще на будке немного (не всю конфу, увы).

Вообще, очень интересно заниматься двумя продуктами (CLion и ReSharper C++) которые в какой-то мере конкурирую друг с другом по feature set, хотя и покрывают разный технологический стек. Я конечно фанат «конвергенции» когда разные разработки можно свести в один большой продукт, но в данном случае боюсь этому не бывать.

Для тех кому С++ «до лампочки» скажу лишь что этот язык – живее всех живых, и что бы не творилось в мире в плане популярности языков, как минимум 3 конкретные индустрии – game dev, embedded и quant finance – использовали и будут использовать именно C/C++. Меня конечно из всего этого интересует последняя (финансовая математика), поэтому я сейчас в процессе обкатывания библиотек (таких как QuantLib) под вышеупомянутыми продуктами.

Как ни странно, в этом году я не смог попользоваться ни D ни F#. Вообще мне кажется что с учетом прогресса в С++ (а также того факта что рано или поздно, ну может лет через 5, вы сможете шипить C# native), использование альтернативных языков хоть и возможно, но скорее «для души» нежели ради денег.

Гаджеты

В этом году не удалось попробовать ничего нового. 13-дюймовый айпад так и не зарелизили, а больше ничего перспективного и не было. Да, единственное, я наконец-то перешел на Blackberry, но в отличии от других людей, которые считают что писать блог-посты про то «как я перешел на WP/Android/iOS» это уместно, для меня это – ниже плинтуса. Так что и не надейтесь. Скажу так: BB Q10 меня всем устраивает, и точка.

А, да, к концу года Intel устроил распродажу Xeon Phi по $200 штука. Вот вам вполне гаджет, но поскольку нынешние разработчики о performance знают лишь краем уха, все это мимо цели. Наверное потому такая и цена, да.

Социалочка

Как человек которые сидит по 16 часов в день (с перерывами) за компом, моя социальная жизнь ограничена всякими эвентами вроде .NEXT, NDC London, выступлениями на user-группах в таких злачных местах как Таллинн или Рига, ну вот собственно и всё. И не то чтобы я планирую как-то это status quo менять.

Чего вообще пропало из жизни так это всякие посиделки с родственниками. Мне кажется в 21-м веке никто никому не нужен, и люди тебе в основном звонят только когда им чего-то от тебя надо. Да, это тотальная деградация, но с другой стороны, следует признать что не все люди вот прям такие интересные. Я например достаточно унылый: я могу разве что деньги обсуждать.

Политика и экономика

В этом году случился какой-то эпик фейл в РФ. Все уже надеялись что отношения с западом будут как-то но развиваться, и тут нате вам Украина. Причем весь разлад поначалу пошел именно на экономической почве: правительство Украины не захотело подписывать договор с ЕС, а люди взяли и смекнули что это как бы плохо, т.к. что покупать у РФ и таможенного союза – непонтятно, а вот в ЕС есть печеньки, Amazon.de и иже с ними.

Дальше последовал «захват» Крыма, сакнции, и хоть все и трубят изо всех дыр что де сакнции бессмысленные и на нас не влияют, но факт таков, что среднестатистический россиянин потерял как минимум 50% покупательной способности, если не больше. Так что санкции оказались не просто болезненными, а прям катастрофическими. Поэтому USDRUB на момент написания этого поста выглядит вот как-то так:

usdrub_epic_fail

Больше всего мне кажется народ офигел от сбитого Боинга (строго говоря, год оказался горазд на падения азиатских самолетов, да и паромам тоже не повезло). Я сам в тот момент летел из СПб в UK (хорошо что не не над Украиной маршрут), прилетаю, включаю BBC, а там такое… я бы тоже озверел, наверное. Ну и конечно тот поток лжи и откровенных фейков на федеральных каналах, не говоря о бреде вроде превратить США в гору радиоактивного пепла… позор, просто позор… ну как так можно позориться-то, а?

Тем временем… в магазинах, где и изначально-то нормальной еды не было (в РФ нормальная еда только в ресторанах, на прилавках ее нет), теперь вообще все плохо. Хуже может быть только голод и еда по талонам, как в 90е – и не стоит зарекаться что их не будет. Но с другой стороны в магазинах и телевизоров-то нет (упс!) а это значит что все такие богатые-шоколадные и вообще все супер, хотя когда у меня на графике USDRUB добил до 80, я думал что вот оно – market crash, дальше дефолты, девальвация и гори оно все огнем. А доллар за 500 это не так нереально как может показаться. И эти рынки не закрыть, разве что можно сделать рубль неконвертируемым, но это такой же адъ как и отключение SWIFT (которое, кстати, еще может случиться). Поразительно что каналы вроде RBC могут еще шутить (хотя улыбаться определенно не время):

Ну да ладно, про РФ забудем, ну ее – вот в Штатах все вообще шоколадно: DJIA бьет рекорды, NASA планирует лететь на Марс, Elon Musk продолжает выпускать новые модели Tesla (единственная машина, которую вообще стоит покупать), ну и капиталиация Apple или Google теперь больше чем весь рынок РФ. Так что повод для оптимизма в плане инвестиций есть. Ну и шортить USDRUB никто не запрещает… хотя как не запрещает, в Британии уже косяки с этим.

Итого

Как-то действительно получилось в этот раз. И я не в коей мере не ставлю себе целью на следующий год написать 100500 статей. Мне бы книгу дописать. Кстати, одну уже сделал, вот ловите, MATLAB Succintly (бесплатно и про MATLAB). А сейчас я как бы пишу серьезную книгу для Apress, тему не скажу, не просите. Может и не допишу вообще, т.к. денег в этом мало, а тщеславие можно тешить и по-другому.

Еще, я почти уверен, что я убью devtalk.net и spbalt.net. Касательно первого — один блог-пост за год (wordpress так говорит!) это не стоит того, а что касается spbalt.net то извините, но поскольку никто все еще не готов ничего рассказывать на встречах юзергрупп (а я насильно заставлять никого не буду!) то имеем что имеем. Впрочем, имхо .NEXT-а должно хватать. Но если не хватает — велкам в личку!

И еще, я сейчас занят небольшим e-learning проектом, так что что-нибудь я точно вам покажу в следующем году. Когда – это вопрос.

С Новым Годом! ■

Written by Dmitri

31 декабря 2014 at 12:31

Опубликовано в Technology

Мысли о выборе технологий

10 комментариев

Мне кажется, что идеальной состояние любой технологически ориентированной компании — это диверсификация. Иначе просто рискуешь нарваться на то что ты внезапно нерелевантен. Хороший пример – это разработчики Windows Mobile (это то, что предшествовало Windows Phone) — их по сути всех «кинули», и все их скилы (там .NET Compact Framework и иже с ним) внезапно стали бесполезны.

Я тут думал на тему того, на базе чего имеет смысл сегодня начинать писать новый продукт. Идеи у меня конечно все направлены в сторону «веба», т.к. и ежу понятно, что идеальная стратегия для конечного пользователя – это «облако», даже если это облако приватное, т.е. существует в пределах инфраструктуры компании, а не отдано «на аутсорс» всяким Amazon, Microsoft и так далее.

Так вот, все равно, в большинстве случае, на стороне сервера я прихожу к тому, что единственный возможный вариант для создания back-end’а чего бы то ни было это С++, и что все Java/.NET решения особого смысла для высокотехнологичных решений (а не решений в стиле «база для веб-мордочки») не имеют. Агрументация моя примерно такая:

  • Мы просто не можем позволить себе ограничивать себя в плане операционной системы. А это значит что можно использовать только то, что работает везде. Следовательно, сразу «отпадает» .NET т.к. при всей возможной опенсорсности Roslyn, использовать Mono я пока как-то не хочу.

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

  • Единственный способ воспользоваться интересным железом, которое на сервере совсем не зазорно размещать, это C/C++. Хотя по правде сказать, у Java есть поползновения сделать поддержку GPU на базе Aparapi (этот фреймворк в свое время поставляла ATI для использования OpenCL из Java), но GPU – это ведь только одна, причем не самая гибкая, технология ускорения вычислений.

Можно, конечно, использовать целый набор языков программирования — все равно в вебе придется использовать JS, например — но мне кажется что если использовать С++ как основу, то уже распыляться не имеет особого смысла. .NET и Java являются языками производительности (productivity languages), но мне кажется что они скорее являются языками лени. Конечно, разработка на С++ на первом этапе медленнее, зато преимущества, мне кажется, очень даже существенны:

  • Инструментарий (профиляторы, анализаторы) намного более зрелый

  • Библиотеки тоже намного более зрелые

  • Возможность оптимизации для конкретной архитектуры. (Надеяться на то векторизацию от какого-нть JIT компилятора – наивно.)

  • Намного более вменяемые подходы к параллелизации, как на декларативном (OpenMP) так и императивном уровне.

  • И да, тот факт что специфичные устройства (в моем случае – Tesla, Xeon Phi и FPGA) — всем могут быть запрограммированы на С++. Хотя в последнем случае все сложнее, т.к. OpenCL, который доступен для этих целей, мне пока не импонирует. Но рано или поздно придется и на него посмотреть.

Нравится вам это или нет, но типичные процессы рано или поздно все-таки перетекут в «удаленные» структуры, которые будут выделять на наши тривиальные задачи намного бо́льшие ресурсы чем те, которые может предоставить ваш ноутбук или рабочая станция. А соответственно, все эти кластеры тоже нужно программировать так, чтобы взаимодействие между машинами было наиболее прозрачным. И для этих целей у нас есть такие вещи как MPI, которые позволят строить гетерогенные сети как из машин, так и из устройств вроде Xeon Phi.

Конечно все это идиллия, и C#/Java программисты будут ругаться и плеваться от одного вида ручного управления памятью. Но зато если вы с самого начала работаете с ручным выделением/уничтожением, умными указателями и соответствующими паттернами использования, то вас уже ничего не должно пугать.

Written by Dmitri

18 апреля 2014 at 23:40

Опубликовано в Technology