SlideShare a Scribd company logo
1 of 101
Download to read offline
В презентации содержится 33 слайда с кодом, сцены насилия,
негуманного обращения с разработчиками и жестокого рефакторинга
Беременным женщинам, детям, лицам страдающим паранойей и
неспособностью воспринимать код, а также менеджерам
от просмотра рекомендуется воздержаться
Как сменить язык
программирования
и не притащить старые привычки в новый мир
@mogilnikov
18 лет стажа
18 лет стажа
Некоторые ролики на
YouTube начинаются с чего-то
похожего
Опыт
C# (Win)
Erlang (Web)
Ruby (Web)
Delphi (Win)
Опыт
C# (Win)
Erlang (Web)
Ruby (Web)
C++ (Win)
Как это началось
Герой
Босс
Босс
Пишем на C#!
Да ну?
…
Ну да!
А есть возражения?
Герой
Ладно
Задача
Написать простой биллинг:
счета, деньги, валюты…
вот это всё
Впереди 20 слайдов с кодом подряд.
Не забывайте дышать!
Диаграмма классов
public class Owner : IOwner
{
public Owner(string title, string castle, string words, Money initBalance)
{
Title = title;
Castle = castle;
Words = words;
Account = new Account(initBalance.Currency, initBalance.Amount);
}
public IAccount Account { get; set; }
public string Title { get; private set; }
public string Words { get; private set; }
public string Castle { get; private set; }
}
public class Account : IAccount
{
public Account(Currency currency, decimal initialBalance)
{
Id = Guid.NewGuid().ToString();
Currency = currency;
InitialBalance = initialBalance;
_transactions = new List<ITransaction>();
}
public string Id { get; private set; }
public Currency Currency { get; private set; }
public decimal InitialBalance { get; private set; }
private readonly List<ITransaction> _transactions;
public IEnumerable<ITransaction> Transactions
{
get { return _transactions; }
}
…
}
public class Account : IAccount
{
…
public void AddTransaction(ITransaction transaction)
{
if (_transactions.Any(t => t.Id == transaction.Id))
throw new ApplicationException("Hodor?");
if (transaction.Account != this)
throw new ApplicationException("Hodor!");
_transactions.Add(transaction);
}
public Money GetBalance()
{
var amount = InitialBalance +
_transactions.Sum(transaction => transaction.Amount);
return new Money(amount, Currency);
}
}
public class Transaction : ITransaction
{
public Transaction(IAccount account, decimal amount, string comment)
{
Id = Guid.NewGuid().ToString();
Comment = comment;
Amount = amount;
Account = account;
}
public string Id { get; private set; }
public IAccount Account { get; private set; }
public decimal Amount { get; private set; }
public ITransaction Reference { get; private set; }
public string Comment { get; private set; }
}
public class Money
{
public Money(decimal amount, Currency currency)
{
Amount = amount;
Currency = currency;
}
public decimal Amount { get; private set; }
public Currency Currency { get; private set; }
}
public enum Currency
{
Dragons,
Stags,
Groats,
Pennies
}
public void Show()
{
var starksInitMoney = new Money(1500, Currency.Stags);
var lannistersInitMoney = new Money(9999, Currency.Dragons);
var starks = new Owner("House Stark", "Winterfell", "Winter is Coming",
starksInitMoney);
var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!",
lannistersInitMoney);
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
var money = new Money(100, Currency.Dragons);
_transferService.Transfer(starks.Account, lannisters.Account, money,
"Pwned by Lannisters");
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
}
public void Show()
{
var starksInitMoney = new Money(1500, Currency.Stags);
var lannistersInitMoney = new Money(9999, Currency.Dragons);
var starks = new Owner("House Stark", "Winterfell", "Winter is Coming",
starksInitMoney);
var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!",
lannistersInitMoney);
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
var money = new Money(100, Currency.Dragons);
_transferService.Transfer(starks.Account, lannisters.Account, money,
"Pwned by Lannisters");
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
}
public class ReceiptConsolePrinter : IReceiptConsolePrinter
{
private readonly IKingsMentalStateCalculator _kingsMentalStateCalculator;
public ReceiptConsolePrinter(IKingsMentalStateCalculator kingsMentalStateCalculator)
{
_kingsMentalStateCalculator = kingsMentalStateCalculator;
}
public void Print(IOwner owner)
{
var balance = owner.Account.GetBalance();
Console.WriteLine("----------- RECEIPT -----------");
Console.WriteLine("Customer: {0} ({1})", owner.Title, owner.Words);
Console.WriteLine("Balance: {0} {1}", balance.Amount, balance.Currency);
Console.WriteLine("King's envy: {0}", _kingsMentalStateCalculator.GetEnvy(owner));
Console.WriteLine("-------------------------------");
Console.WriteLine();
}
}
public class ReceiptConsolePrinter : IReceiptConsolePrinter
{
private readonly IKingsMentalStateCalculator _kingsMentalStateCalculator;
public ReceiptConsolePrinter(IKingsMentalStateCalculator kingsMentalStateCalculator)
{
_kingsMentalStateCalculator = kingsMentalStateCalculator;
}
public void Print(IOwner owner)
{
var balance = owner.Account.GetBalance();
Console.WriteLine("----------- RECEIPT -----------");
Console.WriteLine("Customer: {0} ({1})", owner.Title, owner.Words);
Console.WriteLine("Balance: {0} {1}", balance.Amount, balance.Currency);
Console.WriteLine("King's envy: {0}", _kingsMentalStateCalculator.GetEnvy(owner));
Console.WriteLine("-------------------------------");
Console.WriteLine();
}
}
public class KingsMentalStateCalculator : IKingsMentalStateCalculator
{
private const decimal KingsEnvyThresholdGroats = 100;
private const decimal KingsGrace = 1000;
private readonly ICurrencyConverter _currencyConverter;
public KingsMentalStateCalculator(ICurrencyConverter currencyConverter)
{
_currencyConverter = currencyConverter;
}
public int GetEnvy(IOwner owner)
{
var balance = owner.Account.GetBalance();
var balanceInGroats = _currencyConverter.Convert(balance.Currency, Currency.Groats,
balance.Amount);
var incomesWithoutTrash = owner.Account.Transactions
.Select(t => _currencyConverter.Convert(owner.Account.Currency,Currency.Groats,
t.Amount))
.Where(amount => amount > KingsEnvyThresholdGroats);
var transactionsCountToEnvy = incomesWithoutTrash.Count();
if (transactionsCountToEnvy == 0) transactionsCountToEnvy = 1;
var envy = balanceInGroats/(transactionsCountToEnvy*KingsGrace);
return Convert.ToInt32(envy);
}
}
public class KingsMentalStateCalculator : IKingsMentalStateCalculator
{
private const decimal KingsEnvyThresholdGroats = 100;
private const decimal KingsGrace = 1000;
private readonly ICurrencyConverter _currencyConverter;
public KingsMentalStateCalculator(ICurrencyConverter currencyConverter)
{
_currencyConverter = currencyConverter;
}
public int GetEnvy(IOwner owner)
{
var balance = owner.Account.GetBalance();
var balanceInGroats = _currencyConverter.Convert(balance.Currency, Currency.Groats,
balance.Amount);
var incomesWithoutTrash = owner.Account.Transactions
.Select(t => _currencyConverter.Convert(owner.Account.Currency,Currency.Groats,
t.Amount))
.Where(amount => amount > KingsEnvyThresholdGroats);
var transactionsCountToEnvy = incomesWithoutTrash.Count();
if (transactionsCountToEnvy == 0) transactionsCountToEnvy = 1;
var envy = balanceInGroats/(transactionsCountToEnvy*KingsGrace);
return Convert.ToInt32(envy);
}
}
public class CurrencyConverter : ICurrencyConverter
{
private static readonly Dictionary<Currency, decimal> DragonExchangeRates =
new Dictionary<Currency, decimal>
{
{Currency.Dragons, 1m},
{Currency.Stags, 8.1m},
{Currency.Groats, 121.4m},
{Currency.Pennies, 268m},
};
public decimal Convert(Currency from, Currency to, decimal amount)
{
var fromRate = DragonExchangeRates[from];
var toRate = DragonExchangeRates[to];
return toRate*amount/fromRate;
}
}
public void Show()
{
var starksInitMoney = new Money(1500, Currency.Stags);
var lannistersInitMoney = new Money(9999, Currency.Dragons);
var starks = new Owner("House Stark", "Winterfell", "Winter is Coming",
starksInitMoney);
var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!",
lannistersInitMoney);
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
var money = new Money(100, Currency.Dragons);
_transferService.Transfer(starks.Account, lannisters.Account, money,
"Pwned by Lannisters");
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
}
public class TransferService : ITransferService
{
private readonly ICurrencyConverter _currencyConverter;
public TransferService(ICurrencyConverter currencyConverter)
{
_currencyConverter = currencyConverter;
}
public void Transfer(IAccount from, IAccount to, Money money, string comment)
{
var minusAmount = _currencyConverter.Convert(money.Currency, from.Currency,
money.Amount);
var plusAmount = _currencyConverter.Convert(money.Currency, to.Currency,
money.Amount);
var t1 = new Transaction(from, -minusAmount, comment);
var t2 = new Transaction(to, plusAmount, comment);
from.AddTransaction(t1);
to.AddTransaction(t2);
}
}
public void Show()
{
var starksInitMoney = new Money(1500, Currency.Stags);
var lannistersInitMoney = new Money(9999, Currency.Dragons);
var starks = new Owner("House Stark", "Winterfell", "Winter is Coming",
starksInitMoney);
var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!",
lannistersInitMoney);
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
var money = new Money(100, Currency.Dragons);
_transferService.Transfer(starks.Account, lannisters.Account, money,
"Pwned by Lannisters");
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
}
----------- RECEIPT -----------
Customer: House Stark (Winter is Coming)
Balance: 1500 Stags
King's envy: 22
-------------------------------
----------- RECEIPT -----------
Customer: House Lannister (Hear Me Roar!)
Balance: 9999 Dragons
King's envy: 1214
-------------------------------
----------- RECEIPT -----------
Customer: House Stark (Winter is Coming)
Balance: 690.0 Stags
King's envy: 10
-------------------------------
----------- RECEIPT -----------
Customer: House Lannister (Hear Me Roar!)
Balance: 10099 Dragons
King's envy: 1226
-------------------------------
Всё просто!
Owner!
Currency!
Money!
ReceiptConsolePrinter
Account!
CurrencyConverter??!!
Transaction!
TransferService?
KingsMentalStateCalculator?!
Босс доволен
Ай, молодец!
Только пример так себе
Проблема босса
Программировать на
статически типизированных языках?
В моём королевстве???!!!
Босс
Блин, надо было
использовать dynamic
Новый работодатель
Новый работодатель
Пишем на Ruby!
Герой
Не надо всё
переписывать! И так
работает же!
Новый работодатель
…
Новый работодатель
Герой
Ладно
Герой
Ведь Ruby - это как C#,
только интерпретируемый и с
утиной типизацией!
class Owner
attr_reader :title, :castle, :words, :account
def initialize(title, castle, words, init_balance)
@title = title
@castle = castle
@words = words
@account = Account.new(init_balance.currency, init_balance.amount)
end
end
public class Owner : IOwner
{
public Owner(string title, string castle, string words, Money initBalance)
{
Title = title;
Castle = castle;
Words = words;
Account = new Account(initBalance.Currency, initBalance.Amount);
}
public IAccount Account { get; set; }
public string Title { get; private set; }
public string Words { get; private set; }
public string Castle { get; private set; }
}
class Account
attr_reader :id, :currency, :initial_balance, :transactions
def initialize(currency, initial_balance)
@id = SecureRandom.uuid
@currency = currency
@initial_balance = initial_balance
@transactions = []
end
…
end
public class Account : IAccount
{
public Account(Currency currency, decimal initialBalance)
{
Id = Guid.NewGuid().ToString();
Currency = currency;
InitialBalance = initialBalance;
_transactions = new List<ITransaction>();
}
public string Id { get; private set; }
public Currency Currency { get; private set; }
public decimal InitialBalance { get; private set; }
private readonly List<ITransaction> _transactions;
public IEnumerable<ITransaction> Transactions
{
get { return _transactions; }
}
…
}
public class Account : IAccount
{
…
public void AddTransaction(ITransaction transaction)
{
if (_transactions.Any(t => t.Id == transaction.Id))
throw new ApplicationException("Hodor?");
if (transaction.Account != this)
throw new ApplicationException("Hodor!");
_transactions.Add(transaction);
}
…
}
class Account
…
def add_transaction(transaction)
if @transactions.any? { |t| t.id == transaction.id }
raise StandardError.new("Hodor?")
end
if transaction.account != self
raise StandardError.new("Hodor!")
end
@transactions.push(transaction)
end
…
end
public class Account : IAccount
{
…
public Money GetBalance()
{
var amount = InitialBalance + _transactions.Sum(transaction => transaction.Amount);
return new Money(amount, Currency);
}
}
class Account
…
def get_balance
amount = initial_balance + transactions.sum { |t| t.amount }
return Money.new(amount, currency)
end
end
public class Transaction : ITransaction
{
public Transaction(IAccount account, decimal amount, string comment)
{
Id = Guid.NewGuid().ToString();
Comment = comment;
Amount = amount;
Account = account;
}
public string Id { get; private set; }
public IAccount Account { get; private set; }
public decimal Amount { get; private set; }
public ITransaction Reference { get; private set; }
public string Comment { get; private set; }
}
class Transaction
attr_reader :id, :account, :amount, :reference, :comment
def initialize(account, amount, comment)
@id = SecureRandom.uuid
@comment = comment
@amount = amount
@account = account
end
end
public class Money
{
public Money(decimal amount, Currency currency)
{
Amount = amount;
Currency = currency;
}
public decimal Amount { get; private set; }
public Currency Currency { get; private set; }
}
class Money
attr_reader :amount, :currency
def initialize(amount, currency)
@amount = amount
@currency = currency
end
end
public enum Currency
{
Dragons,
Stags,
Groats,
Pennies
}
module Currency
DRAGONS = 0
STAGS = 1
GROATS = 2
PENNIES = 3
def self.name_of(value)
constants.find { |name| const_get(name) == value }.capitalize
end
end
public void Show()
{
var starksInitMoney = new Money(1500, Currency.Stags);
var lannistersInitMoney = new Money(9999, Currency.Dragons);
var starks = new Owner("House Stark", "Winterfell", "Winter is Coming",
starksInitMoney);
var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!",
lannistersInitMoney);
…
}
def show
starks_init_money = Money.new(1500, Currency::STAGS)
lannisters_init_money = Money.new(9999, Currency::DRAGONS)
starks = Owner.new("House Stark", "Winterfell",
"Winter is Coming", starks_init_money)
lannisters = Owner.new("House Lannister", "Casterly Rock",
"Hear Me Roar!", lannisters_init_money)
…
end
public void Show()
{
…
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
var money = new Money(100, Currency.Dragons);
_transferService.Transfer(starks.Account, lannisters.Account, money,
"Pwned by Lannisters");
_receiptConsolePrinter.Print(starks);
_receiptConsolePrinter.Print(lannisters);
}
def show
…
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
money = Money.new(100, Currency::DRAGONS)
@transfer_service.transfer(starks.account, lannisters.account, money,
"Pwned by Lannisters")
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
end
Профсоюз Ruby-разработчиков потребовал
вырезать сцены чрезмерного насилия над
языком
def show
starks_init_money = Money.new(1500, Currency::STAGS)
lannisters_init_money = Money.new(9999, Currency::DRAGONS)
starks = Owner.new("House Stark", "Winterfell", "Winter is Coming",
starks_init_money)
lannisters = Owner.new("House Lannister", "Casterly Rock", "Hear Me Roar!»,
lannisters_init_money)
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
money = Money.new(100, Currency::DRAGONS)
@transfer_service.transfer(starks.account, lannisters.account, money,
"Pwned by Lannisters")
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
end
Итог
Герой
Ну, как?
CTO
Менеджер проекта
CEO
Ой
Их код не прошёл Code Review
Дорогие
детишки, поможем
программисту?
Или пускай
повесит пока?
В чём была проблема?
В чём была проблема?
Механически перенёс код в
другой синтаксис
Это новый взгляд
на окружающий мир
Новый язык программирования
Другой менталитет
Как объекты реального мира
представляются в коде?
Другой менталитет
Как производится декомпозиция?
Другой менталитет
Как повторно использовать код?
Другой менталитет
Как код обменивается данными
с другим кодом?
Другой менталитет
Какие практики признаны порочными,
а какие правильными?
Какой менталитет у Ruby
I hope to see Ruby help every programmer in the world to be productive,
and to enjoy programming, and to be happy.
That is the primary purpose of Ruby language.
Matz
Какой менталитет у Ruby
Акцент на
скорость разработки
и высокую читаемость кода
Ruby пятью «словами»
Объектно-ориентированный
Динамическая типизация
Метапрограммирование
Культ тестов
Влияние функционального программирования
Объектно-ориентированный
Объект - значимая сущность предметной
области, и ничего больше
Никаких «сервисов», «хелперов» и прочего
Динамическая типизация
Не только аргументы и
переменные без типов, но и
другой взгляд на декомпозицию
Более гибкий код
Метапрограммирование
Код, генерируемый «на лету»,
в зависимости от данных
Повышает читаемость и удобство
Культ тестов
Можно «замокать» любой
метод любого объекта
Пишется «читаемый», а не «тестируемый» код
Влияние ФП
Лямбды везде, повсюду
FP-фаги одобряют
Как писать на Ruby?
№1
Купи макбук
№1: миксины
module SharedCode
def say_hello
puts "Hello, my name is #{self.class.name}!"
end
end
class Vasya
include SharedCode
end
class Petya
include SharedCode
end
class Dyatel
end
Vasya.new.say_hello # => "Hello, my name is Vasya!"
Petya.new.say_hello # => "Hello, my name is Petya!"
Dyatel.new.say_hello # => NoMethodError: undefined method
№2: метапрограммирование
class Demo
# Read fields list from DB
[:name, :phone, :age].each do |field|
define_method "find_by_#{field}" do |value|
puts "Search for field '#{field}' with value '#{value}'"
end
end
end
demo = Demo.new
demo.find_by_name "Vasya" # => Search for field 'name' with value 'Vasya'
demo.find_by_age 14 # => Search for field 'age' with value '14'
№3: скобки, убирай скобки!!111
lalala(op, pa) => lalala op, pa
Как должен выглядеть код?
def show
starks_init_money = Money.new(1500, Currency::STAGS)
lannisters_init_money = Money.new(9999, Currency::DRAGONS)
starks = Owner.new("House Stark", "Winterfell", "Winter is Coming",
starks_init_money)
lannisters = Owner.new("House Lannister", "Casterly Rock", "Hear Me Roar!»,
lannisters_init_money)
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
money = Money.new(100, Currency::DRAGONS)
@transfer_service.transfer(starks.account, lannisters.account, money,
"Pwned by Lannisters")
@receipt_console_printer.print(starks)
@receipt_console_printer.print(lannisters)
end
def show
starks_init_money = Money.new 1500, Currency::STAGS
lannisters_init_money = Money.new 9999, Currency::DRAGONS
starks = Owner.new "House Stark", "Winterfell", "Winter is Coming",
starks_init_money
lannisters = Owner.new "House Lannister", "Casterly Rock", "Hear Me Roar!»,
lannisters_init_money
@receipt_console_printer.print starks
@receipt_console_printer.print lannisters
money = Money.new 100, Currency::DRAGONS
@transfer_service.transfer starks.account, lannisters.account, money,
"Pwned by Lannisters"
@receipt_console_printer.print starks
@receipt_console_printer.print lannisters
end
Выкинь «вредные» объекты
И скобки :)
module TransferService
def transfer(source_account, target_account, money, comment)
minus = money.to(source_account.currency)
plus = money.to(target_account.currency)
t1 = Transaction.new source_account, -minus.amount, comment
t2 = Transaction.new target_account, plus.amount, comment
source_account.add_transaction t1
target_account.add_transaction t2
end
end
module ReceiptConsolePrinter
include KingsMentalStateCalculator
def print_receipt_for(owner)
balance = owner.account.balance
puts "----------- RECEIPT -----------"
puts "Customer: #{owner.title} (#{owner.words})"
puts "Balance: #{balance}"
puts "King's envy: #{kings_envy_for owner}"
puts "-------------------------------"
puts ""
end
end
class Demo
include ReceiptConsolePrinter
include TransferService
def show
starks_init_money = Money.new 1500, Currency::STAGS
lannisters_init_money = Money.new 9999, Currency::DRAGONS
starks = Owner.new "House Stark", "Winterfell", "Winter is Coming",
starks_init_money
lannisters = Owner.new "House Lannister", "Casterly Rock", "Hear Me Roar!»,
lannisters_init_money
print_receipt_for starks
print_receipt_for lannisters
money = Money.new 100, Currency::DRAGONS
transfer starks.account, lannisters.account, money, "Pwned by Lannisters"
print_receipt_for starks
print_receipt_for lannisters
end
end
Создавай объекты стильно!
module Demo
module MoneyMethods
CurrencyConverter::RATES.keys.each do |currency_name|
define_method currency_name.to_s do
Money.new self, currency_name
end
end
end
end
class Float
include Demo::MoneyMethods
end
class Fixnum
include Demo::MoneyMethods
end
class Demo
include ReceiptConsolePrinter
include TransferService
def show
starks = Owner.new "House Stark", "Winterfell", "Winter is Coming",
1500.stags
lannisters = Owner.new "House Lannister", "Casterly Rock",
"Hear Me Roar!", 9999.dragons
print_receipt_for starks
print_receipt_for lannisters
transfer starks.account, lannisters.account, 100.dragons, "Pwned by Lannisters"
print_receipt_for starks
print_receipt_for lannisters
end
end
И напиши уже тесты!
Роскомнадзор потребовал
удалить код, разжигающий ненависть по
отношению к тестам, написанным не на
динамических языках
Так как учить новые языки?
№1
Разберитесь в менталитете
языка
Найдите статью
Так как учить новые языки?
№2
Выполните упражнения
Есть для множества языков
Так как учить новые языки?
№3
Посмотрите код какого-нибудь
проекта
Небольшого, берегите мозг
Так как учить новые языки?
№4
Портируйте свой код
Покажите его кому-нибудь
Так как учить новые языки?
№5
Пишите код
Так как учить новые языки?
№6
Пишите код
Так как учить новые языки?
№7
А вот сейчас можно прочитать
книжку
Систематизирует знания
Изучайте новые языки!
Изучайте новые языки!
For The Greater Good!
Где найти код
https://github.com/amogil/dump-2015-c-sharp
https://github.com/amogil/dump-2015-ruby
Благодарности. Ну, правда

More Related Content

More from it-people

«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Coit-people
 
«Scrapy internals» Александр Сибиряков, Scrapinghub
«Scrapy internals» Александр Сибиряков, Scrapinghub«Scrapy internals» Александр Сибиряков, Scrapinghub
«Scrapy internals» Александр Сибиряков, Scrapinghubit-people
 
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrainsit-people
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologiesit-people
 
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
«Ещё один Поиск Яндекса» Александр Кошелев, Яндексit-people
 
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...it-people
 
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalrit-people
 
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...it-people
 
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАНit-people
 
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банкit-people
 
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Coit-people
 
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНСit-people
 
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...it-people
 
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologiesit-people
 
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn Systemit-people
 
«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologiesit-people
 
«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндексit-people
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...it-people
 
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognicianit-people
 
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...it-people
 

More from it-people (20)

«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
«Про аналитику и серебряные пули» Александр Подсобляев, Rambler&Co
 
«Scrapy internals» Александр Сибиряков, Scrapinghub
«Scrapy internals» Александр Сибиряков, Scrapinghub«Scrapy internals» Александр Сибиряков, Scrapinghub
«Scrapy internals» Александр Сибиряков, Scrapinghub
 
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
«Отладка в Python 3.6: Быстрее, Выше, Сильнее» Елизавета Шашкова, JetBrains
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
 
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
«Ещё один Поиск Яндекса» Александр Кошелев, Яндекс
 
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
«How I Learned to Stop Worrying and Love the BFG: нагрузочное тестирование со...
 
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
«Write once run anywhere — почём опиум для народа?» Игорь Новиков, Scalr
 
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
«Gensim — тематическое моделирование для людей» Иван Меньших, Лев Константино...
 
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН«Тотальный контроль производительности» Михаил Юматов, ЦИАН
«Тотальный контроль производительности» Михаил Юматов, ЦИАН
 
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
«Детские болезни live-чата» Ольга Сентемова, Тинькофф Банк
 
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
«Микросервисы наносят ответный удар!» Олег Чуркин, Rambler&Co
 
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
 
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
«Что такое serverless-архитектура и как с ней жить?» Николай Марков, Aligned ...
 
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
«Python на острие бритвы: PyPy project» Александр Кошкин, Positive Technologies
 
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
«PyWat. А хорошо ли вы знаете Python?» Александр Швец, Marilyn System
 
«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies«(Без)опасный Python», Иван Цыганов, Positive Technologies
«(Без)опасный Python», Иван Цыганов, Positive Technologies
 
«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс«Python of Things», Кирилл Борисов, Яндекс
«Python of Things», Кирилл Борисов, Яндекс
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
 
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
«Клиенту и серверу нужно поговорить» Прокопов Никита, Cognician
 
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
«Кошелек или деньги: сложный выбор между памятью и процессором» Алексеенко Иг...
 

Recently uploaded

一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样ayvbos
 
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency""Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency"growthgrids
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirtrahman018755
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...gajnagarg
 
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...meghakumariji156
 
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理AS
 
Local Call Girls in Seoni 9332606886 HOT & SEXY Models beautiful and charmin...
Local Call Girls in Seoni  9332606886 HOT & SEXY Models beautiful and charmin...Local Call Girls in Seoni  9332606886 HOT & SEXY Models beautiful and charmin...
Local Call Girls in Seoni 9332606886 HOT & SEXY Models beautiful and charmin...kumargunjan9515
 
Leading-edge AI Image Generators of 2024
Leading-edge AI Image Generators of 2024Leading-edge AI Image Generators of 2024
Leading-edge AI Image Generators of 2024SOFTTECHHUB
 
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查ydyuyu
 
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样ayvbos
 
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrStory Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrHenryBriggs2
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdfMatthew Sinclair
 
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdfMatthew Sinclair
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfJOHNBEBONYAP1
 
20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdf20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdfMatthew Sinclair
 
Indian Escort in Abu DHabi 0508644382 Abu Dhabi Escorts
Indian Escort in Abu DHabi 0508644382 Abu Dhabi EscortsIndian Escort in Abu DHabi 0508644382 Abu Dhabi Escorts
Indian Escort in Abu DHabi 0508644382 Abu Dhabi EscortsMonica Sydney
 
一比一原版犹他大学毕业证如何办理
一比一原版犹他大学毕业证如何办理一比一原版犹他大学毕业证如何办理
一比一原版犹他大学毕业证如何办理F
 
💚 Call Girls Bahraich 9332606886 High Profile Call Girls You Can Get The S...
💚 Call Girls Bahraich   9332606886  High Profile Call Girls You Can Get The S...💚 Call Girls Bahraich   9332606886  High Profile Call Girls You Can Get The S...
💚 Call Girls Bahraich 9332606886 High Profile Call Girls You Can Get The S...Sareena Khatun
 
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查ydyuyu
 
Abu Dhabi Escorts Service 0508644382 Escorts in Abu Dhabi
Abu Dhabi Escorts Service 0508644382 Escorts in Abu DhabiAbu Dhabi Escorts Service 0508644382 Escorts in Abu Dhabi
Abu Dhabi Escorts Service 0508644382 Escorts in Abu DhabiMonica Sydney
 

Recently uploaded (20)

一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
 
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency""Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirt
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
 
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...
Tadepalligudem Escorts Service Girl ^ 9332606886, WhatsApp Anytime Tadepallig...
 
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理
一比一原版(Dundee毕业证书)英国爱丁堡龙比亚大学毕业证如何办理
 
Local Call Girls in Seoni 9332606886 HOT & SEXY Models beautiful and charmin...
Local Call Girls in Seoni  9332606886 HOT & SEXY Models beautiful and charmin...Local Call Girls in Seoni  9332606886 HOT & SEXY Models beautiful and charmin...
Local Call Girls in Seoni 9332606886 HOT & SEXY Models beautiful and charmin...
 
Leading-edge AI Image Generators of 2024
Leading-edge AI Image Generators of 2024Leading-edge AI Image Generators of 2024
Leading-edge AI Image Generators of 2024
 
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
 
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
 
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrStory Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
 
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
 
20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdf20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdf
 
Indian Escort in Abu DHabi 0508644382 Abu Dhabi Escorts
Indian Escort in Abu DHabi 0508644382 Abu Dhabi EscortsIndian Escort in Abu DHabi 0508644382 Abu Dhabi Escorts
Indian Escort in Abu DHabi 0508644382 Abu Dhabi Escorts
 
一比一原版犹他大学毕业证如何办理
一比一原版犹他大学毕业证如何办理一比一原版犹他大学毕业证如何办理
一比一原版犹他大学毕业证如何办理
 
💚 Call Girls Bahraich 9332606886 High Profile Call Girls You Can Get The S...
💚 Call Girls Bahraich   9332606886  High Profile Call Girls You Can Get The S...💚 Call Girls Bahraich   9332606886  High Profile Call Girls You Can Get The S...
💚 Call Girls Bahraich 9332606886 High Profile Call Girls You Can Get The S...
 
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查
原版制作美国爱荷华大学毕业证(iowa毕业证书)学位证网上存档可查
 
Abu Dhabi Escorts Service 0508644382 Escorts in Abu Dhabi
Abu Dhabi Escorts Service 0508644382 Escorts in Abu DhabiAbu Dhabi Escorts Service 0508644382 Escorts in Abu Dhabi
Abu Dhabi Escorts Service 0508644382 Escorts in Abu Dhabi
 

DUMP-2015: «Как сменить язык программирования и не притащить старые привычки в новый мир» Алексей Могильников, Artec Group Inc

  • 1. В презентации содержится 33 слайда с кодом, сцены насилия, негуманного обращения с разработчиками и жестокого рефакторинга Беременным женщинам, детям, лицам страдающим паранойей и неспособностью воспринимать код, а также менеджерам от просмотра рекомендуется воздержаться
  • 2. Как сменить язык программирования и не притащить старые привычки в новый мир @mogilnikov
  • 4. 18 лет стажа Некоторые ролики на YouTube начинаются с чего-то похожего
  • 7.
  • 13. Ну да! А есть возражения?
  • 15. Задача Написать простой биллинг: счета, деньги, валюты… вот это всё
  • 16. Впереди 20 слайдов с кодом подряд. Не забывайте дышать!
  • 18. public class Owner : IOwner { public Owner(string title, string castle, string words, Money initBalance) { Title = title; Castle = castle; Words = words; Account = new Account(initBalance.Currency, initBalance.Amount); } public IAccount Account { get; set; } public string Title { get; private set; } public string Words { get; private set; } public string Castle { get; private set; } }
  • 19. public class Account : IAccount { public Account(Currency currency, decimal initialBalance) { Id = Guid.NewGuid().ToString(); Currency = currency; InitialBalance = initialBalance; _transactions = new List<ITransaction>(); } public string Id { get; private set; } public Currency Currency { get; private set; } public decimal InitialBalance { get; private set; } private readonly List<ITransaction> _transactions; public IEnumerable<ITransaction> Transactions { get { return _transactions; } } … }
  • 20. public class Account : IAccount { … public void AddTransaction(ITransaction transaction) { if (_transactions.Any(t => t.Id == transaction.Id)) throw new ApplicationException("Hodor?"); if (transaction.Account != this) throw new ApplicationException("Hodor!"); _transactions.Add(transaction); } public Money GetBalance() { var amount = InitialBalance + _transactions.Sum(transaction => transaction.Amount); return new Money(amount, Currency); } }
  • 21. public class Transaction : ITransaction { public Transaction(IAccount account, decimal amount, string comment) { Id = Guid.NewGuid().ToString(); Comment = comment; Amount = amount; Account = account; } public string Id { get; private set; } public IAccount Account { get; private set; } public decimal Amount { get; private set; } public ITransaction Reference { get; private set; } public string Comment { get; private set; } }
  • 22. public class Money { public Money(decimal amount, Currency currency) { Amount = amount; Currency = currency; } public decimal Amount { get; private set; } public Currency Currency { get; private set; } } public enum Currency { Dragons, Stags, Groats, Pennies }
  • 23. public void Show() { var starksInitMoney = new Money(1500, Currency.Stags); var lannistersInitMoney = new Money(9999, Currency.Dragons); var starks = new Owner("House Stark", "Winterfell", "Winter is Coming", starksInitMoney); var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!", lannistersInitMoney); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); var money = new Money(100, Currency.Dragons); _transferService.Transfer(starks.Account, lannisters.Account, money, "Pwned by Lannisters"); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); }
  • 24. public void Show() { var starksInitMoney = new Money(1500, Currency.Stags); var lannistersInitMoney = new Money(9999, Currency.Dragons); var starks = new Owner("House Stark", "Winterfell", "Winter is Coming", starksInitMoney); var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!", lannistersInitMoney); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); var money = new Money(100, Currency.Dragons); _transferService.Transfer(starks.Account, lannisters.Account, money, "Pwned by Lannisters"); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); }
  • 25. public class ReceiptConsolePrinter : IReceiptConsolePrinter { private readonly IKingsMentalStateCalculator _kingsMentalStateCalculator; public ReceiptConsolePrinter(IKingsMentalStateCalculator kingsMentalStateCalculator) { _kingsMentalStateCalculator = kingsMentalStateCalculator; } public void Print(IOwner owner) { var balance = owner.Account.GetBalance(); Console.WriteLine("----------- RECEIPT -----------"); Console.WriteLine("Customer: {0} ({1})", owner.Title, owner.Words); Console.WriteLine("Balance: {0} {1}", balance.Amount, balance.Currency); Console.WriteLine("King's envy: {0}", _kingsMentalStateCalculator.GetEnvy(owner)); Console.WriteLine("-------------------------------"); Console.WriteLine(); } }
  • 26. public class ReceiptConsolePrinter : IReceiptConsolePrinter { private readonly IKingsMentalStateCalculator _kingsMentalStateCalculator; public ReceiptConsolePrinter(IKingsMentalStateCalculator kingsMentalStateCalculator) { _kingsMentalStateCalculator = kingsMentalStateCalculator; } public void Print(IOwner owner) { var balance = owner.Account.GetBalance(); Console.WriteLine("----------- RECEIPT -----------"); Console.WriteLine("Customer: {0} ({1})", owner.Title, owner.Words); Console.WriteLine("Balance: {0} {1}", balance.Amount, balance.Currency); Console.WriteLine("King's envy: {0}", _kingsMentalStateCalculator.GetEnvy(owner)); Console.WriteLine("-------------------------------"); Console.WriteLine(); } }
  • 27. public class KingsMentalStateCalculator : IKingsMentalStateCalculator { private const decimal KingsEnvyThresholdGroats = 100; private const decimal KingsGrace = 1000; private readonly ICurrencyConverter _currencyConverter; public KingsMentalStateCalculator(ICurrencyConverter currencyConverter) { _currencyConverter = currencyConverter; } public int GetEnvy(IOwner owner) { var balance = owner.Account.GetBalance(); var balanceInGroats = _currencyConverter.Convert(balance.Currency, Currency.Groats, balance.Amount); var incomesWithoutTrash = owner.Account.Transactions .Select(t => _currencyConverter.Convert(owner.Account.Currency,Currency.Groats, t.Amount)) .Where(amount => amount > KingsEnvyThresholdGroats); var transactionsCountToEnvy = incomesWithoutTrash.Count(); if (transactionsCountToEnvy == 0) transactionsCountToEnvy = 1; var envy = balanceInGroats/(transactionsCountToEnvy*KingsGrace); return Convert.ToInt32(envy); } }
  • 28. public class KingsMentalStateCalculator : IKingsMentalStateCalculator { private const decimal KingsEnvyThresholdGroats = 100; private const decimal KingsGrace = 1000; private readonly ICurrencyConverter _currencyConverter; public KingsMentalStateCalculator(ICurrencyConverter currencyConverter) { _currencyConverter = currencyConverter; } public int GetEnvy(IOwner owner) { var balance = owner.Account.GetBalance(); var balanceInGroats = _currencyConverter.Convert(balance.Currency, Currency.Groats, balance.Amount); var incomesWithoutTrash = owner.Account.Transactions .Select(t => _currencyConverter.Convert(owner.Account.Currency,Currency.Groats, t.Amount)) .Where(amount => amount > KingsEnvyThresholdGroats); var transactionsCountToEnvy = incomesWithoutTrash.Count(); if (transactionsCountToEnvy == 0) transactionsCountToEnvy = 1; var envy = balanceInGroats/(transactionsCountToEnvy*KingsGrace); return Convert.ToInt32(envy); } }
  • 29. public class CurrencyConverter : ICurrencyConverter { private static readonly Dictionary<Currency, decimal> DragonExchangeRates = new Dictionary<Currency, decimal> { {Currency.Dragons, 1m}, {Currency.Stags, 8.1m}, {Currency.Groats, 121.4m}, {Currency.Pennies, 268m}, }; public decimal Convert(Currency from, Currency to, decimal amount) { var fromRate = DragonExchangeRates[from]; var toRate = DragonExchangeRates[to]; return toRate*amount/fromRate; } }
  • 30. public void Show() { var starksInitMoney = new Money(1500, Currency.Stags); var lannistersInitMoney = new Money(9999, Currency.Dragons); var starks = new Owner("House Stark", "Winterfell", "Winter is Coming", starksInitMoney); var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!", lannistersInitMoney); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); var money = new Money(100, Currency.Dragons); _transferService.Transfer(starks.Account, lannisters.Account, money, "Pwned by Lannisters"); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); }
  • 31. public class TransferService : ITransferService { private readonly ICurrencyConverter _currencyConverter; public TransferService(ICurrencyConverter currencyConverter) { _currencyConverter = currencyConverter; } public void Transfer(IAccount from, IAccount to, Money money, string comment) { var minusAmount = _currencyConverter.Convert(money.Currency, from.Currency, money.Amount); var plusAmount = _currencyConverter.Convert(money.Currency, to.Currency, money.Amount); var t1 = new Transaction(from, -minusAmount, comment); var t2 = new Transaction(to, plusAmount, comment); from.AddTransaction(t1); to.AddTransaction(t2); } }
  • 32. public void Show() { var starksInitMoney = new Money(1500, Currency.Stags); var lannistersInitMoney = new Money(9999, Currency.Dragons); var starks = new Owner("House Stark", "Winterfell", "Winter is Coming", starksInitMoney); var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!", lannistersInitMoney); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); var money = new Money(100, Currency.Dragons); _transferService.Transfer(starks.Account, lannisters.Account, money, "Pwned by Lannisters"); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); }
  • 33. ----------- RECEIPT ----------- Customer: House Stark (Winter is Coming) Balance: 1500 Stags King's envy: 22 ------------------------------- ----------- RECEIPT ----------- Customer: House Lannister (Hear Me Roar!) Balance: 9999 Dragons King's envy: 1214 ------------------------------- ----------- RECEIPT ----------- Customer: House Stark (Winter is Coming) Balance: 690.0 Stags King's envy: 10 ------------------------------- ----------- RECEIPT ----------- Customer: House Lannister (Hear Me Roar!) Balance: 10099 Dragons King's envy: 1226 -------------------------------
  • 36. Проблема босса Программировать на статически типизированных языках? В моём королевстве???!!!
  • 44. Герой Ведь Ruby - это как C#, только интерпретируемый и с утиной типизацией!
  • 45. class Owner attr_reader :title, :castle, :words, :account def initialize(title, castle, words, init_balance) @title = title @castle = castle @words = words @account = Account.new(init_balance.currency, init_balance.amount) end end public class Owner : IOwner { public Owner(string title, string castle, string words, Money initBalance) { Title = title; Castle = castle; Words = words; Account = new Account(initBalance.Currency, initBalance.Amount); } public IAccount Account { get; set; } public string Title { get; private set; } public string Words { get; private set; } public string Castle { get; private set; } }
  • 46. class Account attr_reader :id, :currency, :initial_balance, :transactions def initialize(currency, initial_balance) @id = SecureRandom.uuid @currency = currency @initial_balance = initial_balance @transactions = [] end … end public class Account : IAccount { public Account(Currency currency, decimal initialBalance) { Id = Guid.NewGuid().ToString(); Currency = currency; InitialBalance = initialBalance; _transactions = new List<ITransaction>(); } public string Id { get; private set; } public Currency Currency { get; private set; } public decimal InitialBalance { get; private set; } private readonly List<ITransaction> _transactions; public IEnumerable<ITransaction> Transactions { get { return _transactions; } } … }
  • 47. public class Account : IAccount { … public void AddTransaction(ITransaction transaction) { if (_transactions.Any(t => t.Id == transaction.Id)) throw new ApplicationException("Hodor?"); if (transaction.Account != this) throw new ApplicationException("Hodor!"); _transactions.Add(transaction); } … } class Account … def add_transaction(transaction) if @transactions.any? { |t| t.id == transaction.id } raise StandardError.new("Hodor?") end if transaction.account != self raise StandardError.new("Hodor!") end @transactions.push(transaction) end … end
  • 48. public class Account : IAccount { … public Money GetBalance() { var amount = InitialBalance + _transactions.Sum(transaction => transaction.Amount); return new Money(amount, Currency); } } class Account … def get_balance amount = initial_balance + transactions.sum { |t| t.amount } return Money.new(amount, currency) end end
  • 49. public class Transaction : ITransaction { public Transaction(IAccount account, decimal amount, string comment) { Id = Guid.NewGuid().ToString(); Comment = comment; Amount = amount; Account = account; } public string Id { get; private set; } public IAccount Account { get; private set; } public decimal Amount { get; private set; } public ITransaction Reference { get; private set; } public string Comment { get; private set; } } class Transaction attr_reader :id, :account, :amount, :reference, :comment def initialize(account, amount, comment) @id = SecureRandom.uuid @comment = comment @amount = amount @account = account end end
  • 50. public class Money { public Money(decimal amount, Currency currency) { Amount = amount; Currency = currency; } public decimal Amount { get; private set; } public Currency Currency { get; private set; } } class Money attr_reader :amount, :currency def initialize(amount, currency) @amount = amount @currency = currency end end
  • 51. public enum Currency { Dragons, Stags, Groats, Pennies } module Currency DRAGONS = 0 STAGS = 1 GROATS = 2 PENNIES = 3 def self.name_of(value) constants.find { |name| const_get(name) == value }.capitalize end end
  • 52. public void Show() { var starksInitMoney = new Money(1500, Currency.Stags); var lannistersInitMoney = new Money(9999, Currency.Dragons); var starks = new Owner("House Stark", "Winterfell", "Winter is Coming", starksInitMoney); var lannisters = new Owner("House Lannister", "Casterly Rock", "Hear Me Roar!", lannistersInitMoney); … } def show starks_init_money = Money.new(1500, Currency::STAGS) lannisters_init_money = Money.new(9999, Currency::DRAGONS) starks = Owner.new("House Stark", "Winterfell", "Winter is Coming", starks_init_money) lannisters = Owner.new("House Lannister", "Casterly Rock", "Hear Me Roar!", lannisters_init_money) … end
  • 53. public void Show() { … _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); var money = new Money(100, Currency.Dragons); _transferService.Transfer(starks.Account, lannisters.Account, money, "Pwned by Lannisters"); _receiptConsolePrinter.Print(starks); _receiptConsolePrinter.Print(lannisters); } def show … @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) money = Money.new(100, Currency::DRAGONS) @transfer_service.transfer(starks.account, lannisters.account, money, "Pwned by Lannisters") @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) end
  • 54. Профсоюз Ruby-разработчиков потребовал вырезать сцены чрезмерного насилия над языком
  • 55. def show starks_init_money = Money.new(1500, Currency::STAGS) lannisters_init_money = Money.new(9999, Currency::DRAGONS) starks = Owner.new("House Stark", "Winterfell", "Winter is Coming", starks_init_money) lannisters = Owner.new("House Lannister", "Casterly Rock", "Hear Me Roar!», lannisters_init_money) @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) money = Money.new(100, Currency::DRAGONS) @transfer_service.transfer(starks.account, lannisters.account, money, "Pwned by Lannisters") @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) end Итог
  • 57. CTO
  • 59. CEO
  • 60. Ой Их код не прошёл Code Review
  • 63. В чём была проблема?
  • 64. В чём была проблема? Механически перенёс код в другой синтаксис
  • 65. Это новый взгляд на окружающий мир Новый язык программирования
  • 66. Другой менталитет Как объекты реального мира представляются в коде?
  • 69. Другой менталитет Как код обменивается данными с другим кодом?
  • 70. Другой менталитет Какие практики признаны порочными, а какие правильными?
  • 71. Какой менталитет у Ruby I hope to see Ruby help every programmer in the world to be productive, and to enjoy programming, and to be happy. That is the primary purpose of Ruby language. Matz
  • 72. Какой менталитет у Ruby Акцент на скорость разработки и высокую читаемость кода
  • 73. Ruby пятью «словами» Объектно-ориентированный Динамическая типизация Метапрограммирование Культ тестов Влияние функционального программирования
  • 74. Объектно-ориентированный Объект - значимая сущность предметной области, и ничего больше Никаких «сервисов», «хелперов» и прочего
  • 75. Динамическая типизация Не только аргументы и переменные без типов, но и другой взгляд на декомпозицию Более гибкий код
  • 76. Метапрограммирование Код, генерируемый «на лету», в зависимости от данных Повышает читаемость и удобство
  • 77. Культ тестов Можно «замокать» любой метод любого объекта Пишется «читаемый», а не «тестируемый» код
  • 78. Влияние ФП Лямбды везде, повсюду FP-фаги одобряют
  • 79. Как писать на Ruby? №1 Купи макбук
  • 80. №1: миксины module SharedCode def say_hello puts "Hello, my name is #{self.class.name}!" end end class Vasya include SharedCode end class Petya include SharedCode end class Dyatel end Vasya.new.say_hello # => "Hello, my name is Vasya!" Petya.new.say_hello # => "Hello, my name is Petya!" Dyatel.new.say_hello # => NoMethodError: undefined method
  • 81. №2: метапрограммирование class Demo # Read fields list from DB [:name, :phone, :age].each do |field| define_method "find_by_#{field}" do |value| puts "Search for field '#{field}' with value '#{value}'" end end end demo = Demo.new demo.find_by_name "Vasya" # => Search for field 'name' with value 'Vasya' demo.find_by_age 14 # => Search for field 'age' with value '14'
  • 82. №3: скобки, убирай скобки!!111 lalala(op, pa) => lalala op, pa
  • 83. Как должен выглядеть код? def show starks_init_money = Money.new(1500, Currency::STAGS) lannisters_init_money = Money.new(9999, Currency::DRAGONS) starks = Owner.new("House Stark", "Winterfell", "Winter is Coming", starks_init_money) lannisters = Owner.new("House Lannister", "Casterly Rock", "Hear Me Roar!», lannisters_init_money) @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) money = Money.new(100, Currency::DRAGONS) @transfer_service.transfer(starks.account, lannisters.account, money, "Pwned by Lannisters") @receipt_console_printer.print(starks) @receipt_console_printer.print(lannisters) end
  • 84. def show starks_init_money = Money.new 1500, Currency::STAGS lannisters_init_money = Money.new 9999, Currency::DRAGONS starks = Owner.new "House Stark", "Winterfell", "Winter is Coming", starks_init_money lannisters = Owner.new "House Lannister", "Casterly Rock", "Hear Me Roar!», lannisters_init_money @receipt_console_printer.print starks @receipt_console_printer.print lannisters money = Money.new 100, Currency::DRAGONS @transfer_service.transfer starks.account, lannisters.account, money, "Pwned by Lannisters" @receipt_console_printer.print starks @receipt_console_printer.print lannisters end Выкинь «вредные» объекты И скобки :)
  • 85. module TransferService def transfer(source_account, target_account, money, comment) minus = money.to(source_account.currency) plus = money.to(target_account.currency) t1 = Transaction.new source_account, -minus.amount, comment t2 = Transaction.new target_account, plus.amount, comment source_account.add_transaction t1 target_account.add_transaction t2 end end
  • 86. module ReceiptConsolePrinter include KingsMentalStateCalculator def print_receipt_for(owner) balance = owner.account.balance puts "----------- RECEIPT -----------" puts "Customer: #{owner.title} (#{owner.words})" puts "Balance: #{balance}" puts "King's envy: #{kings_envy_for owner}" puts "-------------------------------" puts "" end end
  • 87. class Demo include ReceiptConsolePrinter include TransferService def show starks_init_money = Money.new 1500, Currency::STAGS lannisters_init_money = Money.new 9999, Currency::DRAGONS starks = Owner.new "House Stark", "Winterfell", "Winter is Coming", starks_init_money lannisters = Owner.new "House Lannister", "Casterly Rock", "Hear Me Roar!», lannisters_init_money print_receipt_for starks print_receipt_for lannisters money = Money.new 100, Currency::DRAGONS transfer starks.account, lannisters.account, money, "Pwned by Lannisters" print_receipt_for starks print_receipt_for lannisters end end
  • 88. Создавай объекты стильно! module Demo module MoneyMethods CurrencyConverter::RATES.keys.each do |currency_name| define_method currency_name.to_s do Money.new self, currency_name end end end end class Float include Demo::MoneyMethods end class Fixnum include Demo::MoneyMethods end
  • 89. class Demo include ReceiptConsolePrinter include TransferService def show starks = Owner.new "House Stark", "Winterfell", "Winter is Coming", 1500.stags lannisters = Owner.new "House Lannister", "Casterly Rock", "Hear Me Roar!", 9999.dragons print_receipt_for starks print_receipt_for lannisters transfer starks.account, lannisters.account, 100.dragons, "Pwned by Lannisters" print_receipt_for starks print_receipt_for lannisters end end
  • 90. И напиши уже тесты! Роскомнадзор потребовал удалить код, разжигающий ненависть по отношению к тестам, написанным не на динамических языках
  • 91. Так как учить новые языки? №1 Разберитесь в менталитете языка Найдите статью
  • 92. Так как учить новые языки? №2 Выполните упражнения Есть для множества языков
  • 93. Так как учить новые языки? №3 Посмотрите код какого-нибудь проекта Небольшого, берегите мозг
  • 94. Так как учить новые языки? №4 Портируйте свой код Покажите его кому-нибудь
  • 95. Так как учить новые языки? №5 Пишите код
  • 96. Так как учить новые языки? №6 Пишите код
  • 97. Так как учить новые языки? №7 А вот сейчас можно прочитать книжку Систематизирует знания