SlideShare uma empresa Scribd logo
1 de 84
Baixar para ler offline
No Hugging, No Learning
Olaf Alders
Toronto Perl Mongers
Aug 25, 2016
@olafalders (Twitter)
oalders (GitHub)
OALDERS (PAUSE)
https://github.com/oalders/no-hugging-no-learning
The Problem
Building an app that can track and chart (almost)
anything that is available via 3rd party APIs
No screen scraping
No ToS violations
Doing this in my limited spare time
The Solution
Build an app based solely on what I already know:
"No hugging, no learning"
Of the three programmer virtues (laziness,
impatience and hubris), I would let laziness be my
guiding light
I tried to self-impose a real lack of intellectual
curiosity
The Evolution
The App
Before
Some command line scripts as a proof of concept
This became a Dancer (1) app run via Plack
Pros
Dancer apps are easy to get up and running
Cons
I didn't really love the Dancer (1) syntax
Dancer2 was still quite new and the plugin support
wasn't there yet
After
I moved to a Mojolicous Lite app run via Plack
I then transitioned to a full Mojo app
Run via morbo in development
Run via hypnotoad in production
morbo
By default watches your lesystem for changes
and then reloads your app
hypnotoad
Zero downtime restarts
You don't need to provide your own init script
If you don't care about zero downtime or just want
the prefork server, you have that option
perl script/myapp prefork
same con g args as morbo/daemon
Did I learn?
I partly became familiar with Mojo via my day job,
but I did have to do a fair bit of learning on my
own.
I was not familiar with Hypnotoad , but luckily that
was a pretty easy transition. The docs are really
good.
Authentication
Before
Mozilla's Persona
Pros
Pretty easy to con gure
All anyone really needs is an email address
Cons
Issues getting it to work of ine
No widespread adoption
Felt like the rst 80% was easy but the last 20%
was eating into my time
After
OAuth via any of the available integrations
I needed this anyway in order to get user data, so
it keeps things simpler to have Persona out of the
mix
With Mozilla no longer 100% behind Persona, it
becomes a less attractive solution
most non-technical users won't be familiar with
it at this point anyway
SSL Everywhere
Looked brie y into Let's Encrypt via Ansible
Ended up spending USD 10 for a RapidSSL cert
Relational Database
Before
Application data stored in MySQL database
Pros
I'm very familiar with MySQL
I prefer many MySQL tools, like the mysql command
line interface and phpMyAdmin
MySQL replication is dead easy to con gure
Cons
"Foreign keys that point to the renamed table are
not automatically updated. In such cases, you must
drop and re-create the foreign keys in order for
them to function properly."
After
3 Postgres databases
Minion
Application data
Test suite xtures
Did I learn?
Since we use Postgres at $work , I didn't have to
learn a whole lot to make the switch.
The database does a litle bit more than the bare
minimum -- I'm not taking advantage of all that
Postgres has to offer
No jsonb columns just yet
Job Management
Before
cron scripts
After
Minion
Did I learn?
Had basically zero knowledge of Minion
implementation
But, there's not much you need to learn in order to
get up and running
Minimized a lot of really convoluted cron job logic
This probably saved me time in the long run
Minion How To
You don't need to have a full-blown Mojo app to
use Minion
Just create a bare bones app to get started
Use this with your Catalyst, Dancer, [insert
framework here] application
Let's look at how MetaCPAN uses Minion
Create an App
https://github.com/metacpan/metacpan-
api/blob/master/lib/MetaCPAN/Queue.pm
Sets up a tiny Mojo app
Adds Minion tasks in the startup() method
You can see how we trap warnings and log failed
jobs in the _gen_index_task_sub() method
Optionally Create Your Minion
Backend Elsewhere
We've abstracted it out to
https://github.com/metacpan/metacpan-
api/blob/master/lib/MetaCPAN/Queue/Helper.pm
We do this so that we can use an SQLite database
when running under the test harness and a
Postgres database in all other cases
Using SQLite for testing makes our Travis
con guration much easier
This will also allow us more easily to run tests in
parallel
Start Up Your Queue
In development, you can create a 4-5 line script to
start up your queue via morbo
https://github.com/metacpan/metacpan-
api/blob/master/bin/queue.pl
In production we use Daemon::Control to manage
starting and stopping a daemon
https://github.com/metacpan/metacpan-
puppet/blob/master/modules/minion_queue/te
mplates/init.pl.erb
Add Tasks
A task is essentially an anonymous sub which you
can later refer to by name
A job is an instance of a task
$minion->add_task( add_things => sub {
# $job is a Minion::Job object
my ($job, $first, $second) = @_;
$job->finish($first + $second);
});
More Complete Example
$minion->add_task( add_things => sub {
my ($job, $first, $second) = @_;
$job->finish({
message => 'Great!',
total => $first + $second,
});
});
my $id = $minion->enqueue(add_things => [1, 1]);
my $result = $minion->job($id)->info->{result};
$result is now
{ message => 'Great!', total => 2 }
Storing Your Job Result
$job->finish;
$job->finish('Fantastic!');
$job->finish({ foo => 'bar' });
Later, you can nd this arbitrary data in $job->result
Populate Your Queue
enqueue() means "add job to queue"
$app->minion->enqueue( my_task_name => ['foo', 'bar'] );
$self->minion->enqueue(
track_service_resource =>
[{ service_resource_id => $service_resource->id }] =>
{ priority => 1 },
);
priority ranges from 0-X, where X is a positive
integer
jobs with priority 10 will run before jobs with
priority 9 etc
enqueue() options
attempts => 10 (# of times to attempt job)
delay => 3600 (delay this job for 3600 seconds)
parents => [$id1, $id2] (One or more existing jobs
this job depends on, and that need to have
transitioned to the state finished before it can be
processed)
priority => 3 (see previous slide)
queue => 'dexter' (some arbitrary name, defaults
to default )
Minion::Job
https://metacpan.org/pod/Minion::Job
You can set up events to be red on failed and
finished states
Get information via $job->info
$job->is_finished
$job->remove
Much, much more
Inspect Your Queue
On the MetaCPAN Vagrant box:
$ vagrant ssh
$ cd /home/vagrant/metacpan-api/
$ ./bin/run bin/queue.pl minion job -s
{
"active_jobs" => 0,
"active_workers" => 0,
"delayed_jobs" => 0,
"failed_jobs" => 0,
"finished_jobs" => 0,
"inactive_jobs" => 0,
"inactive_workers" => 1
}
Test Your Queue
https://github.com/metacpan/metacpan-
api/blob/master/t/queue.t
use MetaCPAN::Queue;
use Test::More;
use Test::RequiresInternet ( 'cpan.metacpan.org' => 443 );
my $app = MetaCPAN::Queue->new;
my $release = 'https://cpan.metacpan.org/authors/id/O/OA/OALDERS
$app->minion->enqueue(
index_release => [ '--latest', $release ]
);
$app->minion->perform_jobs;
done_testing();
Advanced: Behaviour on Events
https://github.com/jberger/Minion-
Noti er/blob/master/lib/Minion/Noti er.pm#L39-
L56
sub setup_worker {
my $self = shift;
my $dequeue = sub {
my ($worker, $job) = @_;
my $id = $job->id;
$self->transport->send($id, 'dequeue');
$job->on(finished => sub { $self->transport->send($id,
$job->on(failed => sub { $self->transport->send($id,
};
$self->minion->on(worker => sub {
my ($minion, $worker) = @_;
$worker->on(dequeue => $dequeue);
});
return $self
}
Code Context
The preceding code is called like this:
https://github.com/jberger/Minion-
Noti er/blob/master/lib/Mojolicious/Plugin/Minion/
Noti er.pm#L37
Pros
We can replace a failure-prone, forking, long
running process with a series of jobs
If a job fails in an unexpected way, it doesn't
prevent all the other jobs from running
We can check the status of all jobs at any point to
gauge how things are progressing
Jobs which fail can be retried at intervals
We can start an arbitrary number of worker apps
Using Postgres replication MetaCPAN can now
start X workers on 3 different boxes, which gives
us greater scaling when needed
Cons
Minion doesn't come with a handy daemon
handler like hypnotoad , but you can set this stuff all
up yourself pretty easily
There aren't yet a lot of tools to visualize what's
going on with the queue, but again this can be
done pretty easily if you need it.
Database Migrations
Before
Database schema managed by Database::Migrator
Pros
Database::Migrator is what we use at $work
It's pretty simple
In addition to SQL, you can also run Perl scripts as
part of a migration
Cons
Database::Migrator needs to be subclassed, which
means you have to provide a fair bit of
functionality just to get up and running
After
Application and xture databases managed via
App::Sqitch
Minion has its own schema deployment logic
Pros
sqitch handles rollbacks as well as deployment
Optionally can use custom assertions to ensure
that deployments were successful
Cons
There's a lot more going on here, so you probably
have to do a bit of reading before just jumping in
I had to use the CLI rather than the modules
because of some weirdness between Moo and
Moose when I tried to use the modules directly
Did I learn?
Yes, I did have to learn sqitch from scratch
The author (David Wheeler) was extremely helpful
I was able to get it working with my xtures
See Also
Mojo::Pg::Migrations
Mojo::mysql::Migrations
Mojo::SQLite::Migrations
Automation of Deployment
Before
The plan was to use Puppet
Pros
I was already familiar with Puppet
Cons
I was already familiar with Puppet
Even simple things seemed hard
Tired of dealing with hard to debug certi cate
issues
There may have been obvious and easy xes to
my problems, but I couldn't easily nd them
I'm not saying that Puppet isn't a wonderful tool,
but it felt like a bigger hammer than I needed
After
Ansible
Pros
Excellent integration with Vagrant
No need for bootstrapping on the target
deployment machines
It's easily installed via Homebrew on OS X
Has good handling of git submodule
User contributed plugins are trivial to install
Cons
I actually don't have a lot of complaints
Moving from v1 to v2 addressed the few issues
that I ran into
Ansible in Vagrant le
config.vm.provision "ansible" do |ansible|
ansible.verbose = "v"
ansible.playbook = "ansible/site.yml"
ansible.sudo = true
ansible.groups = {
"development" => ["default"],
"webservers" => ["default"],
}
end
Installing Packages
---
- gather_facts: no
hosts: webservers
tasks:
- apt: 'pkg={{item}} state=installed'
name: Install misc apt packages
with_items:
- curl
- ntp
- tree
- unzip
- apt: update_cache=yes cache_valid_time=3600
name: Run the equivalent of "apt-get update"
- apt: upgrade=dist autoremove=true
name: Update all packages to the latest version
Did I learn?
Yes, I had to learn all about Ansible , since I had never
used it before. In the meantime $work has also
switched from puppet to ansible , so it turned out to
be knowledge that I can apply there as well.
Keeping in mind how many hours I've spent battling
Puppet on past projects, I think learning about
Ansible was actually the better, faster choice.
Predictions Which Did Not Change
JS-Driven Charts
Highcharts turned out to be an excellent choice
Excellent docs
Responsive support
I'm also quite happy with the product itself
Twitter Bootstrap
Still a solid choice for a CSS framework
Travis CI
Private repository support is not within my budget
(starts at USD 129/month)
Open Source option works excellently for
https://github.com/oalders/wundercharts-plugin
Carton for Dependency Pinning
This suits my needs ne at this point
https://metacpan.org/pod/Carmel is still listed as
experimental
Vagrant
Initially I just ran the app inside OS X directly
I realized pretty quickly that I wanted to have a
sandbox
I've even got a Vagrantfile for the plugin system
https://github.com/oalders/wundercharts-
plugin/blob/master/Vagrant le
So, anyone who wants to contribute can have a
fully operational, sandboxed system with all of
the modules installed within a matter of
minutes
Code::TidyAll
I use this to tidy as much code as possible
It's enforced via a Git pre-commit hook so that I
don't have to think about it
LWP::ConsoleLogger
I use this a lot when debugging interactions with
3rd party APIs
This only really works when you can get at the UA
which a module is using
I wish more module authors would expose their
user agents
The Mojo equivalent is setting
MOJO_USERAGENT_DEBUG=1
DBIx::Class
Use foreign keys and the schema dumper
automatically sets up relationships for you
Use this trick to enable perltidy to tidy your
schema les:
https://metacpan.org/pod/release/ILMARI/DBIx-
Class-Schema-Loader-
0.07045/lib/DBIx/Class/Schema/Loader/Base.pm
# lter_generated_code
Mojolicious::Plugin::AssetPack
Compress and convert css, less, sass, javascript
and coffeescript les
In development mode you get the individual les
in your template (for easier debugging)
Strict Constructors
MooseX::StrictConstructor
MooX::StrictConstructor
MetaCPAN::Moose
etc
nginx
Ubuntu 14.04.5 LTS
Perl v5.18.2
Things I Hadn't Planned on Using
Wercker
I didn't know this existed
I'm not good about running my test suite after
every change, so I realized I had to automate this
I didn't want to run my own Jenkins/TeamCity/etc
service
I've seen how much con guration can go into
these things and I didn't have the time to mess
with it
Free, concurrent builds for private repositories
Wercker (cont'd)
I didn't want to give it access to all of my private
repositories
I created a BitBucket account (free private
repositories)
Added a new remote to my repository
"bitbucket"
Every time I push to the "bitbucket" remote the
tests are run and I get an email about success or
failure
Protip: if weird errors happen, sometimes you
have to clear your Wercker cache
wrapbootstrap.com
I hadn't even thought about the UI when I started
this project
I bought the "Inspina" theme for USD 18
This gave me solid options for both logged in
and logged out UI
Was trivial to implement and immediately made
my terrible design much better
Since I was already using Bootstrap there
weren't a lot of changes to be made
Date Range Picker
http://www.daterangepicker.com
Easy to use and makes it easy to use sensible
defaults when selecting dates or ranges of dates
Open Source That Came Out of
This
Mojolicious::Plugin::Web::Auth::Site::Spotify
Mojolicious::Plugin::Web::Auth::Site::Runkeeper
WebService::HealthGraph
Code::TidyAll::Plugin::YAML
WWW::Spotify (co-maint)
Patch to WebService::Instagram
I open sourced all of my plugins
WunderCharts Plugins
https://github.com/oalders/wundercharts-plugin
100% open source
I'm in a position to integrate user contributed
patches without open sourcing the entire code
base
For example, if we want to integrate FitBit
Need to create
Mojolicious::Plugin::Web::Auth::Site::FitBit
Need to send a pull request for
WunderCharts::Plugin::FitBit
Third Party Integrations
I didn't have a rm idea of how many I wanted
Got a mixture of OAuth, OAuth2 and no auth
OAuth
Twitter
OAuth 2
Facebook
Instagram
Spotify
GitHub
No authentication required
Hacker News
Don't Count Your Chickens
Instagram apps (unlike the other sites) have a
formal review process
I didn't realize until after my integration was
nished that my use case may not qualify
I did get accepted at the end of the day, but it's a
bit of a coin toss
You need to show them the integration via a
screen cast before you get approval, so it's
possible to do the heavy lifting and still be denied
Success?
Among other things, I ended up having to learn (or
learn more about) the following technologies:
Ansible
BitBucket
Date Range Picker
hypnotoad
Minion
Mojo
Mojolicious::Plugin::AssetPack
Persona
sqitch
Wercker
[also various 3rd party APIs for web services]
Thanks!
To Joel Berger for proofreading the Mojo bits of
an earlier version of this talk
All remaining (or since introduced) errors are my
own
The "Finished" Product
https://wundercharts.com

Mais conteúdo relacionado

Mais procurados

Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...Puppet
 
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Puppet
 
Zero Downtime Deployment with Ansible
Zero Downtime Deployment with AnsibleZero Downtime Deployment with Ansible
Zero Downtime Deployment with AnsibleStein Inge Morisbak
 
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !Florent BENOIT
 
Capifony. Minsk PHP MeetUp #11
Capifony. Minsk PHP MeetUp #11Capifony. Minsk PHP MeetUp #11
Capifony. Minsk PHP MeetUp #11Yury Pliashkou
 
Getting Started with Puppet on Windows - PuppetConf 2014
Getting Started with Puppet on Windows - PuppetConf 2014Getting Started with Puppet on Windows - PuppetConf 2014
Getting Started with Puppet on Windows - PuppetConf 2014Puppet
 
Frontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the likeFrontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the likeDamien Seguin
 
Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014Puppet
 
Develop - Project Scaffolding
Develop - Project ScaffoldingDevelop - Project Scaffolding
Develop - Project ScaffoldingKevin Cao
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidenceJohn Congdon
 
The Challenges of Container Configuration
The Challenges of Container ConfigurationThe Challenges of Container Configuration
The Challenges of Container ConfigurationGareth Rushgrove
 
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...NETWAYS
 
Puppet camp Portland 2015: -windows (1)
Puppet camp Portland 2015: -windows (1)Puppet camp Portland 2015: -windows (1)
Puppet camp Portland 2015: -windows (1)Puppet
 
A Continuous Packaging Pipeline
A Continuous Packaging PipelineA Continuous Packaging Pipeline
A Continuous Packaging PipelineMaciej Pasternacki
 
Painless Deployment with Capistrano
Painless Deployment with CapistranoPainless Deployment with Capistrano
Painless Deployment with CapistranoNick Kugaevsky
 
Automating your workflow with Gulp.js
Automating your workflow with Gulp.jsAutomating your workflow with Gulp.js
Automating your workflow with Gulp.jsBo-Yi Wu
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Puppet
 
Infrastructure = code - 1 year later
Infrastructure = code - 1 year laterInfrastructure = code - 1 year later
Infrastructure = code - 1 year laterChristian Ortner
 
WordPress workflow of the future
WordPress workflow of the futureWordPress workflow of the future
WordPress workflow of the futureEli McMakin
 
"13 ways to run web applications on the Internet" Andrii Shumada
"13 ways to run web applications on the Internet" Andrii Shumada"13 ways to run web applications on the Internet" Andrii Shumada
"13 ways to run web applications on the Internet" Andrii ShumadaFwdays
 

Mais procurados (20)

Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
Puppet Camp Düsseldorf 2014: Continuously Deliver Your Puppet Code with Jenki...
 
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
 
Zero Downtime Deployment with Ansible
Zero Downtime Deployment with AnsibleZero Downtime Deployment with Ansible
Zero Downtime Deployment with Ansible
 
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
 
Capifony. Minsk PHP MeetUp #11
Capifony. Minsk PHP MeetUp #11Capifony. Minsk PHP MeetUp #11
Capifony. Minsk PHP MeetUp #11
 
Getting Started with Puppet on Windows - PuppetConf 2014
Getting Started with Puppet on Windows - PuppetConf 2014Getting Started with Puppet on Windows - PuppetConf 2014
Getting Started with Puppet on Windows - PuppetConf 2014
 
Frontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the likeFrontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the like
 
Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014
 
Develop - Project Scaffolding
Develop - Project ScaffoldingDevelop - Project Scaffolding
Develop - Project Scaffolding
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
 
The Challenges of Container Configuration
The Challenges of Container ConfigurationThe Challenges of Container Configuration
The Challenges of Container Configuration
 
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...
Puppet Camp Berlin 2015: Pedro Pessoa | Puppet at the center of everything - ...
 
Puppet camp Portland 2015: -windows (1)
Puppet camp Portland 2015: -windows (1)Puppet camp Portland 2015: -windows (1)
Puppet camp Portland 2015: -windows (1)
 
A Continuous Packaging Pipeline
A Continuous Packaging PipelineA Continuous Packaging Pipeline
A Continuous Packaging Pipeline
 
Painless Deployment with Capistrano
Painless Deployment with CapistranoPainless Deployment with Capistrano
Painless Deployment with Capistrano
 
Automating your workflow with Gulp.js
Automating your workflow with Gulp.jsAutomating your workflow with Gulp.js
Automating your workflow with Gulp.js
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014
 
Infrastructure = code - 1 year later
Infrastructure = code - 1 year laterInfrastructure = code - 1 year later
Infrastructure = code - 1 year later
 
WordPress workflow of the future
WordPress workflow of the futureWordPress workflow of the future
WordPress workflow of the future
 
"13 ways to run web applications on the Internet" Andrii Shumada
"13 ways to run web applications on the Internet" Andrii Shumada"13 ways to run web applications on the Internet" Andrii Shumada
"13 ways to run web applications on the Internet" Andrii Shumada
 

Destaque

Network Programming With Anyevent
Network Programming With AnyeventNetwork Programming With Anyevent
Network Programming With AnyeventPedro Melo
 
Carton CPAN dependency manager
Carton CPAN dependency managerCarton CPAN dependency manager
Carton CPAN dependency managerTatsuhiko Miyagawa
 
Deploying Plack Web Applications: OSCON 2011
Deploying Plack Web Applications: OSCON 2011Deploying Plack Web Applications: OSCON 2011
Deploying Plack Web Applications: OSCON 2011Tatsuhiko Miyagawa
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012Hiroshi Shibamura
 

Destaque (9)

Network Programming With Anyevent
Network Programming With AnyeventNetwork Programming With Anyevent
Network Programming With Anyevent
 
Carton CPAN dependency manager
Carton CPAN dependency managerCarton CPAN dependency manager
Carton CPAN dependency manager
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
 
CPAN Realtime feed
CPAN Realtime feedCPAN Realtime feed
CPAN Realtime feed
 
Tatsumaki
TatsumakiTatsumaki
Tatsumaki
 
Deploying Plack Web Applications: OSCON 2011
Deploying Plack Web Applications: OSCON 2011Deploying Plack Web Applications: OSCON 2011
Deploying Plack Web Applications: OSCON 2011
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
ZeroMQ in PHP
ZeroMQ in PHPZeroMQ in PHP
ZeroMQ in PHP
 
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012
 

Semelhante a No Hugging, No Learning

Deferred Processing in Ruby - Philly rb - August 2011
Deferred Processing in Ruby - Philly rb - August 2011Deferred Processing in Ruby - Philly rb - August 2011
Deferred Processing in Ruby - Philly rb - August 2011rob_dimarco
 
Synchronous Reads Asynchronous Writes RubyConf 2009
Synchronous Reads Asynchronous Writes RubyConf 2009Synchronous Reads Asynchronous Writes RubyConf 2009
Synchronous Reads Asynchronous Writes RubyConf 2009pauldix
 
Writing & Sharing Great Modules on the Puppet Forge
Writing & Sharing Great Modules on the Puppet ForgeWriting & Sharing Great Modules on the Puppet Forge
Writing & Sharing Great Modules on the Puppet ForgePuppet
 
Python in the land of serverless
Python in the land of serverlessPython in the land of serverless
Python in the land of serverlessDavid Przybilla
 
Cfgmgmt Challenges aren't technical anymore
Cfgmgmt Challenges aren't technical anymoreCfgmgmt Challenges aren't technical anymore
Cfgmgmt Challenges aren't technical anymoreJulien Pivotto
 
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...Paul Jensen
 
Surviving javascript.pptx
Surviving javascript.pptxSurviving javascript.pptx
Surviving javascript.pptxTamas Rev
 
An Introduction to Prometheus (GrafanaCon 2016)
An Introduction to Prometheus (GrafanaCon 2016)An Introduction to Prometheus (GrafanaCon 2016)
An Introduction to Prometheus (GrafanaCon 2016)Brian Brazil
 
The power of mysqlnd plugins
The power of mysqlnd pluginsThe power of mysqlnd plugins
The power of mysqlnd pluginsUlf Wendel
 
Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...Maarten Balliauw
 
Writing & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp BostonWriting & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp BostonPuppet
 
E2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and PuppeteerE2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and PuppeteerPaul Jensen
 
Neo4j Stored Procedure Training Part 1
Neo4j Stored Procedure Training Part 1Neo4j Stored Procedure Training Part 1
Neo4j Stored Procedure Training Part 1Max De Marzi
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyUlf Wendel
 
Care and feeding notes
Care and feeding notesCare and feeding notes
Care and feeding notesPerrin Harkins
 
Adventures in Laravel 5 SunshinePHP 2016 Tutorial
Adventures in Laravel 5 SunshinePHP 2016 TutorialAdventures in Laravel 5 SunshinePHP 2016 Tutorial
Adventures in Laravel 5 SunshinePHP 2016 TutorialJoe Ferguson
 
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017Codemotion
 
Serverless in production, an experience report (codemotion milan)
Serverless in production, an experience report (codemotion milan)Serverless in production, an experience report (codemotion milan)
Serverless in production, an experience report (codemotion milan)Yan Cui
 

Semelhante a No Hugging, No Learning (20)

Function as a Service
Function as a ServiceFunction as a Service
Function as a Service
 
Deferred Processing in Ruby - Philly rb - August 2011
Deferred Processing in Ruby - Philly rb - August 2011Deferred Processing in Ruby - Philly rb - August 2011
Deferred Processing in Ruby - Philly rb - August 2011
 
Synchronous Reads Asynchronous Writes RubyConf 2009
Synchronous Reads Asynchronous Writes RubyConf 2009Synchronous Reads Asynchronous Writes RubyConf 2009
Synchronous Reads Asynchronous Writes RubyConf 2009
 
Writing & Sharing Great Modules on the Puppet Forge
Writing & Sharing Great Modules on the Puppet ForgeWriting & Sharing Great Modules on the Puppet Forge
Writing & Sharing Great Modules on the Puppet Forge
 
Python in the land of serverless
Python in the land of serverlessPython in the land of serverless
Python in the land of serverless
 
Cfgmgmt Challenges aren't technical anymore
Cfgmgmt Challenges aren't technical anymoreCfgmgmt Challenges aren't technical anymore
Cfgmgmt Challenges aren't technical anymore
 
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
End to end testing Single Page Apps & APIs with Cucumber.js and Puppeteer (Em...
 
Surviving javascript.pptx
Surviving javascript.pptxSurviving javascript.pptx
Surviving javascript.pptx
 
An Introduction to Prometheus (GrafanaCon 2016)
An Introduction to Prometheus (GrafanaCon 2016)An Introduction to Prometheus (GrafanaCon 2016)
An Introduction to Prometheus (GrafanaCon 2016)
 
The power of mysqlnd plugins
The power of mysqlnd pluginsThe power of mysqlnd plugins
The power of mysqlnd plugins
 
Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...Sherlock Homepage - A detective story about running large web services - WebN...
Sherlock Homepage - A detective story about running large web services - WebN...
 
Writing & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp BostonWriting & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp Boston
 
E2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and PuppeteerE2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
E2E testing Single Page Apps and APIs with Cucumber.js and Puppeteer
 
Django Girls Tutorial
Django Girls TutorialDjango Girls Tutorial
Django Girls Tutorial
 
Neo4j Stored Procedure Training Part 1
Neo4j Stored Procedure Training Part 1Neo4j Stored Procedure Training Part 1
Neo4j Stored Procedure Training Part 1
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
 
Care and feeding notes
Care and feeding notesCare and feeding notes
Care and feeding notes
 
Adventures in Laravel 5 SunshinePHP 2016 Tutorial
Adventures in Laravel 5 SunshinePHP 2016 TutorialAdventures in Laravel 5 SunshinePHP 2016 Tutorial
Adventures in Laravel 5 SunshinePHP 2016 Tutorial
 
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017
Yan Cui - Serverless in production, an experience report - Codemotion Milan 2017
 
Serverless in production, an experience report (codemotion milan)
Serverless in production, an experience report (codemotion milan)Serverless in production, an experience report (codemotion milan)
Serverless in production, an experience report (codemotion milan)
 

Último

Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...Neha Pandey
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...SofiyaSharma5
 
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Delhi Call girls
 
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl ServiceRussian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl Servicegwenoracqe6
 
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)Delhi Call girls
 
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...Escorts Call Girls
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Callshivangimorya083
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...Diya Sharma
 
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service OnlineCALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Onlineanilsa9823
 
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine ServiceHot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Servicesexy call girls service in goa
 
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$kojalkojal131
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.soniya singh
 
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableCall Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableSeo
 
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024APNIC
 
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663Call Girls Mumbai
 
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝soniya singh
 

Último (20)

Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
 
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
 
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl ServiceRussian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
 
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
 
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...(+971568250507  ))#  Young Call Girls  in Ajman  By Pakistani Call Girls  in ...
(+971568250507 ))# Young Call Girls in Ajman By Pakistani Call Girls in ...
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
 
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service OnlineCALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Online
CALL ON ➥8923113531 🔝Call Girls Lucknow Lucknow best sexual service Online
 
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
 
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine ServiceHot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
 
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
 
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableCall Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
 
Russian Call Girls in %(+971524965298 )# Call Girls in Dubai
Russian Call Girls in %(+971524965298  )#  Call Girls in DubaiRussian Call Girls in %(+971524965298  )#  Call Girls in Dubai
Russian Call Girls in %(+971524965298 )# Call Girls in Dubai
 
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
 
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
 
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
 

No Hugging, No Learning

  • 1. No Hugging, No Learning Olaf Alders Toronto Perl Mongers Aug 25, 2016 @olafalders (Twitter) oalders (GitHub) OALDERS (PAUSE) https://github.com/oalders/no-hugging-no-learning
  • 2. The Problem Building an app that can track and chart (almost) anything that is available via 3rd party APIs No screen scraping No ToS violations Doing this in my limited spare time
  • 3. The Solution Build an app based solely on what I already know: "No hugging, no learning" Of the three programmer virtues (laziness, impatience and hubris), I would let laziness be my guiding light I tried to self-impose a real lack of intellectual curiosity
  • 5. The App Before Some command line scripts as a proof of concept This became a Dancer (1) app run via Plack
  • 6. Pros Dancer apps are easy to get up and running Cons I didn't really love the Dancer (1) syntax Dancer2 was still quite new and the plugin support wasn't there yet
  • 7. After I moved to a Mojolicous Lite app run via Plack I then transitioned to a full Mojo app Run via morbo in development Run via hypnotoad in production
  • 8. morbo By default watches your lesystem for changes and then reloads your app
  • 9. hypnotoad Zero downtime restarts You don't need to provide your own init script If you don't care about zero downtime or just want the prefork server, you have that option perl script/myapp prefork same con g args as morbo/daemon
  • 10. Did I learn? I partly became familiar with Mojo via my day job, but I did have to do a fair bit of learning on my own. I was not familiar with Hypnotoad , but luckily that was a pretty easy transition. The docs are really good.
  • 13. Pros Pretty easy to con gure All anyone really needs is an email address Cons Issues getting it to work of ine No widespread adoption Felt like the rst 80% was easy but the last 20% was eating into my time
  • 14. After OAuth via any of the available integrations I needed this anyway in order to get user data, so it keeps things simpler to have Persona out of the mix With Mozilla no longer 100% behind Persona, it becomes a less attractive solution most non-technical users won't be familiar with it at this point anyway
  • 15. SSL Everywhere Looked brie y into Let's Encrypt via Ansible Ended up spending USD 10 for a RapidSSL cert
  • 17. Before Application data stored in MySQL database
  • 18. Pros I'm very familiar with MySQL I prefer many MySQL tools, like the mysql command line interface and phpMyAdmin MySQL replication is dead easy to con gure Cons "Foreign keys that point to the renamed table are not automatically updated. In such cases, you must drop and re-create the foreign keys in order for them to function properly."
  • 20. Did I learn? Since we use Postgres at $work , I didn't have to learn a whole lot to make the switch. The database does a litle bit more than the bare minimum -- I'm not taking advantage of all that Postgres has to offer No jsonb columns just yet
  • 24. Did I learn? Had basically zero knowledge of Minion implementation But, there's not much you need to learn in order to get up and running Minimized a lot of really convoluted cron job logic This probably saved me time in the long run
  • 25. Minion How To You don't need to have a full-blown Mojo app to use Minion Just create a bare bones app to get started Use this with your Catalyst, Dancer, [insert framework here] application Let's look at how MetaCPAN uses Minion
  • 26. Create an App https://github.com/metacpan/metacpan- api/blob/master/lib/MetaCPAN/Queue.pm Sets up a tiny Mojo app Adds Minion tasks in the startup() method You can see how we trap warnings and log failed jobs in the _gen_index_task_sub() method
  • 27. Optionally Create Your Minion Backend Elsewhere We've abstracted it out to https://github.com/metacpan/metacpan- api/blob/master/lib/MetaCPAN/Queue/Helper.pm We do this so that we can use an SQLite database when running under the test harness and a Postgres database in all other cases Using SQLite for testing makes our Travis con guration much easier This will also allow us more easily to run tests in parallel
  • 28. Start Up Your Queue In development, you can create a 4-5 line script to start up your queue via morbo https://github.com/metacpan/metacpan- api/blob/master/bin/queue.pl In production we use Daemon::Control to manage starting and stopping a daemon https://github.com/metacpan/metacpan- puppet/blob/master/modules/minion_queue/te mplates/init.pl.erb
  • 29. Add Tasks A task is essentially an anonymous sub which you can later refer to by name A job is an instance of a task $minion->add_task( add_things => sub { # $job is a Minion::Job object my ($job, $first, $second) = @_; $job->finish($first + $second); });
  • 30. More Complete Example $minion->add_task( add_things => sub { my ($job, $first, $second) = @_; $job->finish({ message => 'Great!', total => $first + $second, }); }); my $id = $minion->enqueue(add_things => [1, 1]); my $result = $minion->job($id)->info->{result}; $result is now { message => 'Great!', total => 2 }
  • 31. Storing Your Job Result $job->finish; $job->finish('Fantastic!'); $job->finish({ foo => 'bar' }); Later, you can nd this arbitrary data in $job->result
  • 32. Populate Your Queue enqueue() means "add job to queue" $app->minion->enqueue( my_task_name => ['foo', 'bar'] ); $self->minion->enqueue( track_service_resource => [{ service_resource_id => $service_resource->id }] => { priority => 1 }, ); priority ranges from 0-X, where X is a positive integer jobs with priority 10 will run before jobs with priority 9 etc
  • 33. enqueue() options attempts => 10 (# of times to attempt job) delay => 3600 (delay this job for 3600 seconds) parents => [$id1, $id2] (One or more existing jobs this job depends on, and that need to have transitioned to the state finished before it can be processed) priority => 3 (see previous slide) queue => 'dexter' (some arbitrary name, defaults to default )
  • 34. Minion::Job https://metacpan.org/pod/Minion::Job You can set up events to be red on failed and finished states Get information via $job->info $job->is_finished $job->remove Much, much more
  • 35. Inspect Your Queue On the MetaCPAN Vagrant box: $ vagrant ssh $ cd /home/vagrant/metacpan-api/ $ ./bin/run bin/queue.pl minion job -s { "active_jobs" => 0, "active_workers" => 0, "delayed_jobs" => 0, "failed_jobs" => 0, "finished_jobs" => 0, "inactive_jobs" => 0, "inactive_workers" => 1 }
  • 36. Test Your Queue https://github.com/metacpan/metacpan- api/blob/master/t/queue.t use MetaCPAN::Queue; use Test::More; use Test::RequiresInternet ( 'cpan.metacpan.org' => 443 ); my $app = MetaCPAN::Queue->new; my $release = 'https://cpan.metacpan.org/authors/id/O/OA/OALDERS $app->minion->enqueue( index_release => [ '--latest', $release ] ); $app->minion->perform_jobs; done_testing();
  • 37. Advanced: Behaviour on Events https://github.com/jberger/Minion- Noti er/blob/master/lib/Minion/Noti er.pm#L39- L56
  • 38. sub setup_worker { my $self = shift; my $dequeue = sub { my ($worker, $job) = @_; my $id = $job->id; $self->transport->send($id, 'dequeue'); $job->on(finished => sub { $self->transport->send($id, $job->on(failed => sub { $self->transport->send($id, }; $self->minion->on(worker => sub { my ($minion, $worker) = @_; $worker->on(dequeue => $dequeue); }); return $self }
  • 39. Code Context The preceding code is called like this: https://github.com/jberger/Minion- Noti er/blob/master/lib/Mojolicious/Plugin/Minion/ Noti er.pm#L37
  • 40. Pros We can replace a failure-prone, forking, long running process with a series of jobs If a job fails in an unexpected way, it doesn't prevent all the other jobs from running We can check the status of all jobs at any point to gauge how things are progressing Jobs which fail can be retried at intervals We can start an arbitrary number of worker apps Using Postgres replication MetaCPAN can now start X workers on 3 different boxes, which gives us greater scaling when needed
  • 41. Cons Minion doesn't come with a handy daemon handler like hypnotoad , but you can set this stuff all up yourself pretty easily There aren't yet a lot of tools to visualize what's going on with the queue, but again this can be done pretty easily if you need it.
  • 43. Before Database schema managed by Database::Migrator
  • 44. Pros Database::Migrator is what we use at $work It's pretty simple In addition to SQL, you can also run Perl scripts as part of a migration Cons Database::Migrator needs to be subclassed, which means you have to provide a fair bit of functionality just to get up and running
  • 45. After Application and xture databases managed via App::Sqitch Minion has its own schema deployment logic
  • 46. Pros sqitch handles rollbacks as well as deployment Optionally can use custom assertions to ensure that deployments were successful Cons There's a lot more going on here, so you probably have to do a bit of reading before just jumping in I had to use the CLI rather than the modules because of some weirdness between Moo and Moose when I tried to use the modules directly
  • 47. Did I learn? Yes, I did have to learn sqitch from scratch The author (David Wheeler) was extremely helpful I was able to get it working with my xtures
  • 50. Before The plan was to use Puppet
  • 51. Pros I was already familiar with Puppet Cons I was already familiar with Puppet Even simple things seemed hard Tired of dealing with hard to debug certi cate issues There may have been obvious and easy xes to my problems, but I couldn't easily nd them I'm not saying that Puppet isn't a wonderful tool, but it felt like a bigger hammer than I needed
  • 53. Pros Excellent integration with Vagrant No need for bootstrapping on the target deployment machines It's easily installed via Homebrew on OS X Has good handling of git submodule User contributed plugins are trivial to install
  • 54. Cons I actually don't have a lot of complaints Moving from v1 to v2 addressed the few issues that I ran into
  • 55. Ansible in Vagrant le config.vm.provision "ansible" do |ansible| ansible.verbose = "v" ansible.playbook = "ansible/site.yml" ansible.sudo = true ansible.groups = { "development" => ["default"], "webservers" => ["default"], } end
  • 56. Installing Packages --- - gather_facts: no hosts: webservers tasks: - apt: 'pkg={{item}} state=installed' name: Install misc apt packages with_items: - curl - ntp - tree - unzip - apt: update_cache=yes cache_valid_time=3600 name: Run the equivalent of "apt-get update" - apt: upgrade=dist autoremove=true name: Update all packages to the latest version
  • 57. Did I learn? Yes, I had to learn all about Ansible , since I had never used it before. In the meantime $work has also switched from puppet to ansible , so it turned out to be knowledge that I can apply there as well. Keeping in mind how many hours I've spent battling Puppet on past projects, I think learning about Ansible was actually the better, faster choice.
  • 58. Predictions Which Did Not Change
  • 59. JS-Driven Charts Highcharts turned out to be an excellent choice Excellent docs Responsive support I'm also quite happy with the product itself
  • 60. Twitter Bootstrap Still a solid choice for a CSS framework
  • 61. Travis CI Private repository support is not within my budget (starts at USD 129/month) Open Source option works excellently for https://github.com/oalders/wundercharts-plugin
  • 62. Carton for Dependency Pinning This suits my needs ne at this point https://metacpan.org/pod/Carmel is still listed as experimental
  • 63. Vagrant Initially I just ran the app inside OS X directly I realized pretty quickly that I wanted to have a sandbox I've even got a Vagrantfile for the plugin system https://github.com/oalders/wundercharts- plugin/blob/master/Vagrant le So, anyone who wants to contribute can have a fully operational, sandboxed system with all of the modules installed within a matter of minutes
  • 64. Code::TidyAll I use this to tidy as much code as possible It's enforced via a Git pre-commit hook so that I don't have to think about it
  • 65. LWP::ConsoleLogger I use this a lot when debugging interactions with 3rd party APIs This only really works when you can get at the UA which a module is using I wish more module authors would expose their user agents The Mojo equivalent is setting MOJO_USERAGENT_DEBUG=1
  • 66. DBIx::Class Use foreign keys and the schema dumper automatically sets up relationships for you Use this trick to enable perltidy to tidy your schema les: https://metacpan.org/pod/release/ILMARI/DBIx- Class-Schema-Loader- 0.07045/lib/DBIx/Class/Schema/Loader/Base.pm # lter_generated_code
  • 67. Mojolicious::Plugin::AssetPack Compress and convert css, less, sass, javascript and coffeescript les In development mode you get the individual les in your template (for easier debugging)
  • 70. Things I Hadn't Planned on Using
  • 71. Wercker I didn't know this existed I'm not good about running my test suite after every change, so I realized I had to automate this I didn't want to run my own Jenkins/TeamCity/etc service I've seen how much con guration can go into these things and I didn't have the time to mess with it Free, concurrent builds for private repositories
  • 72. Wercker (cont'd) I didn't want to give it access to all of my private repositories I created a BitBucket account (free private repositories) Added a new remote to my repository "bitbucket" Every time I push to the "bitbucket" remote the tests are run and I get an email about success or failure Protip: if weird errors happen, sometimes you have to clear your Wercker cache
  • 73. wrapbootstrap.com I hadn't even thought about the UI when I started this project I bought the "Inspina" theme for USD 18 This gave me solid options for both logged in and logged out UI Was trivial to implement and immediately made my terrible design much better Since I was already using Bootstrap there weren't a lot of changes to be made
  • 74. Date Range Picker http://www.daterangepicker.com Easy to use and makes it easy to use sensible defaults when selecting dates or ranges of dates
  • 75. Open Source That Came Out of This Mojolicious::Plugin::Web::Auth::Site::Spotify Mojolicious::Plugin::Web::Auth::Site::Runkeeper WebService::HealthGraph Code::TidyAll::Plugin::YAML WWW::Spotify (co-maint) Patch to WebService::Instagram I open sourced all of my plugins
  • 76. WunderCharts Plugins https://github.com/oalders/wundercharts-plugin 100% open source I'm in a position to integrate user contributed patches without open sourcing the entire code base
  • 77. For example, if we want to integrate FitBit Need to create Mojolicious::Plugin::Web::Auth::Site::FitBit Need to send a pull request for WunderCharts::Plugin::FitBit
  • 78. Third Party Integrations I didn't have a rm idea of how many I wanted Got a mixture of OAuth, OAuth2 and no auth
  • 80. Don't Count Your Chickens Instagram apps (unlike the other sites) have a formal review process I didn't realize until after my integration was nished that my use case may not qualify I did get accepted at the end of the day, but it's a bit of a coin toss You need to show them the integration via a screen cast before you get approval, so it's possible to do the heavy lifting and still be denied
  • 81. Success? Among other things, I ended up having to learn (or learn more about) the following technologies: Ansible BitBucket Date Range Picker hypnotoad Minion Mojo Mojolicious::Plugin::AssetPack
  • 82. Persona sqitch Wercker [also various 3rd party APIs for web services]
  • 83. Thanks! To Joel Berger for proofreading the Mojo bits of an earlier version of this talk All remaining (or since introduced) errors are my own