domingo, 14 de junio de 2015

Proyecto Vaskit: Socket

Uno de los pilares del proyecto Vaskit para Argentina es poder tener un servicio de socket.

1) Instalar Ubuntu.
2) Instalar Nginx. El mío lo tengo en: /usr/local/nginx

Detener nginx:
cd /usr/local/nginx/sbin
./nginx -s stop

Iniciar nginx:
cd /usr/local/nginx/sbin
./nginx

Recargar config de nginx:
cd /usr/local/nginx/sbin
./nginx -s reload

3) Instalar node.js - El mío quedó en: /home/warodri/node_modules
4) Instalar el múdulo websocket desde node.js:
 
npm install websocket
 
5) Todo está bien explicado en el siguiente sitio;
http://ahoj.io/nodejs-and-websocket-simple-chat-tutorial
También tomo el socket server para hacer un socket con chat publico. También hay un cliente html para demo.

6)Para poder salir al exterior, hice una config en Nginx:

    # PARA WEBSOCKETS
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    upstream websocket {
        server 181.228.31.35:1337;
    }



El sitio full con el Websocket server y client a continuación:



Node.js & WebSocket - Simple chat tutorial


Node.js is a brilliant product. It gives you so much freedom (... and also responsibility) and I think it's ideal for single purpose web servers.
Another great thing is WebSocket. Although Nowadays it's not widely supported (Chrome 14+, Firefox 7, Chrome for iOS, Chrome for Android(?) and maybe IE 10) and it's usage is probably in very specific applications like games or Google Docs. So I wanted to try to make some very simple real world application.
WebSocket requires it's own backend application to communicate with (server side). Therefore you have to write single purpose server and, in my opinion, in this situation node.js is much better than writing your server in Java, C++ or whatever
BTW, if you're looking for some more in-depth information on how WebSockets work I recommend this article Websockets 101.
In this tutorial I'm going to write very simple chat application based on WebSocket and node.js.

Chat features

At the beginning every user can select their name and the server will assign them some random color and will post some system message to the console that a new user just connected. Then the user can post messages. When a user closes the browser window, server will post another system massage to the console that a user has disconnected.
Also, every new user will recieve entire message history.

Live demo

Here's was live demo, feel free to play with in or examine the source code. Just one thing, it might be sometimes broken because I had to restart the server or just something unexpected happened. If so, leave me a comment please., I'll try to put it back online asap.

HTML + CSS

Frontend is very simple HTML and CSS for now. We'll add some JavaScripts later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebSockets - Simple chat</title>
 
<style>
* { font-family:tahoma; font-size:12px; padding:0px; margin:0px; }
p { line-height:18px; }
div { width:500px; margin-left:auto; margin-right:auto;}
#content { padding:5px; background:#ddd; border-radius:5px; overflow-y: scroll;
border:1px solid #CCC; margin-top:10px; height: 160px; }
#input { border-radius:2px; border:1px solid #ccc;
margin-top:10px; padding:5px; width:400px; }
#status { width:88px; display:block; float:left; margin-top:15px; }
</style>
</head>
<body>
<div id="content"></div>
<div>
<span id="status">Connecting...</span>
<input type="text" id="input" disabled="disabled" />
</div>
 
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="./frontend.js"></script>
</body>
</html>
view raw frontend.html hosted with ❤ by GitHub

Communication client -> server, server -> client

Great advantage of WebSocket is two way communication. In this tutorial it means situation when some user sends a message (client -> server) and then server sends that message to all conected users (server -> client) - broadcast.
For client -> server communication I choosed simple text because it's not necessary to wrap it in more complicated structure.
But for server -> client it's a bit more complex. We have to distinguish between 3 different types of message:
  • server assigns a color to user
  • server sends entire message history
  • server broadcasts a message to all users
Therefore every message is a simple JavaScript object encoded into JSON.

Node.js server

Node.js itself doesn't have support for WebSocket but there are already some plugins that implement WebSocket protocols. I've tried two of them:
  • node-websocket-server - very easy to use, but it doesn't support draft-10. That's a big problem because Chrome 14+ supports only draft-10 which is not compatible with older drafts. According to issues on GitHub the autor is working on version 2.0 that should support also draft-10.
  • WebSocket-Node - very easy to and well documented. Supports draft-10 and also older drafts.
In this tutotial I'm going to use the second one, so let's install it with npm (Node Package Manager) which comes together with node.js. There might be a little tricky if you're using Windows because it needs to compile some small part of the module from C++ (read more on github.com).
npm install websocket

WebSocket server template

WebSocket server code template looks like this:
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
    // process HTTP request. Since we're writing just WebSockets server
    // we don't have to implement anything.
});
server.listen(1337, function() { });

// create the server
wsServer = new WebSocketServer({
    httpServer: server
});

// WebSocket server
wsServer.on('request', function(request) {
    var connection = request.accept(null, request.origin);

    // This is the most important callback for us, we'll handle
    // all messages from users here.
    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            // process WebSocket message
        }
    });

    connection.on('close', function(connection) {
        // close user connection
    });
});
So, this is just the most basic skeleton that we'll extend now with more logic.

WebSocket server full source code

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";
 
// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-chat';
 
// Port where we'll run the websocket server
var webSocketsServerPort = 1337;
 
// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
 
/**
* Global variables
*/
// latest 100 messages
var history = [ ];
// list of currently connected clients (users)
var clients = [ ];
 
/**
* Helper function for escaping input strings
*/
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;')
.replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
 
// Array with some colors
var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) { return Math.random() > 0.5; } );
 
/**
* HTTP server
*/
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
 
/**
* WebSocket server
*/
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server. WebSocket request is just
// an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
httpServer: server
});
 
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
 
// accept connection - you should check 'request.origin' to make sure that
// client is connecting from your website
// (http://en.wikipedia.org/wiki/Same_origin_policy)
var connection = request.accept(null, request.origin);
// we need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
var userName = false;
var userColor = false;
 
console.log((new Date()) + ' Connection accepted.');
 
// send back chat history
if (history.length > 0) {
connection.sendUTF(JSON.stringify( { type: 'history', data: history} ));
}
 
// user sent some message
connection.on('message', function(message) {
if (message.type === 'utf8') { // accept only text
if (userName === false) { // first message sent by user is their name
// remember user name
userName = htmlEntities(message.utf8Data);
// get random color and send it back to the user
userColor = colors.shift();
connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
console.log((new Date()) + ' User is known as: ' + userName
+ ' with ' + userColor + ' color.');
 
} else { // log and broadcast the message
console.log((new Date()) + ' Received Message from '
+ userName + ': ' + message.utf8Data);
// we want to keep history of all sent messages
var obj = {
time: (new Date()).getTime(),
text: htmlEntities(message.utf8Data),
author: userName,
color: userColor
};
history.push(obj);
history = history.slice(-100);
 
// broadcast message to all connected clients
var json = JSON.stringify({ type:'message', data: obj });
for (var i=0; i < clients.length; i++) {
clients[i].sendUTF(json);
}
}
}
});
 
// user disconnected
connection.on('close', function(connection) {
if (userName !== false && userColor !== false) {
console.log((new Date()) + " Peer "
+ connection.remoteAddress + " disconnected.");
// remove user from the list of connected clients
clients.splice(index, 1);
// push back user's color to be reused by another user
colors.push(userColor);
}
});
 
});
view raw chat-server.js hosted with ❤ by GitHub
That's all for the server part. I added comments where it was appropriate but I think it's very simple to understand.

Frontend JavaScript

Frontend template

Frontend template is basically just three callback methods:
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
$(function () {
    // if user is running mozilla then use it's built-in WebSocket
    window.WebSocket = window.WebSocket || window.MozWebSocket;

    var connection = new WebSocket('ws://127.0.0.1:1337');

    connection.onopen = function () {
        // connection is opened and ready to use
    };

    connection.onerror = function (error) {
        // an error occurred when sending/receiving data
    };

    connection.onmessage = function (message) {
        // try to decode json (I assume that each message from server is json)
        try {
            var json = JSON.parse(message.data);
        } catch (e) {
            console.log('This doesn\'t look like a valid JSON: ', message.data);
            return;
        }
        // handle incoming message
    };
});

Frontend full source code

Frontend is quiet simple as well, I just added some logging and some enabling/disabling of the input field so it's more user friendly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
$(function () {
"use strict";
 
// for better performance - to avoid searching in DOM
var content = $('#content');
var input = $('#input');
var status = $('#status');
 
// my color assigned by the server
var myColor = false;
// my name sent to the server
var myName = false;
 
// if user is running mozilla then use it's built-in WebSocket
window.WebSocket = window.WebSocket || window.MozWebSocket;
 
// if browser doesn't support WebSocket, just show some notification and exit
if (!window.WebSocket) {
content.html($('<p>', { text: 'Sorry, but your browser doesn\'t '
+ 'support WebSockets.'} ));
input.hide();
$('span').hide();
return;
}
 
// open connection
var connection = new WebSocket('ws://127.0.0.1:1337');
 
connection.onopen = function () {
// first we want users to enter their names
input.removeAttr('disabled');
status.text('Choose name:');
};
 
connection.onerror = function (error) {
// just in there were some problems with conenction...
content.html($('<p>', { text: 'Sorry, but there\'s some problem with your '
+ 'connection or the server is down.' } ));
};
 
// most important part - incoming messages
connection.onmessage = function (message) {
// try to parse JSON message. Because we know that the server always returns
// JSON this should work without any problem but we should make sure that
// the massage is not chunked or otherwise damaged.
try {
var json = JSON.parse(message.data);
} catch (e) {
console.log('This doesn\'t look like a valid JSON: ', message.data);
return;
}
 
// NOTE: if you're not sure about the JSON structure
// check the server source code above
if (json.type === 'color') { // first response from the server with user's color
myColor = json.data;
status.text(myName + ': ').css('color', myColor);
input.removeAttr('disabled').focus();
// from now user can start sending messages
} else if (json.type === 'history') { // entire message history
// insert every single message to the chat window
for (var i=0; i < json.data.length; i++) {
addMessage(json.data[i].author, json.data[i].text,
json.data[i].color, new Date(json.data[i].time));
}
} else if (json.type === 'message') { // it's a single message
input.removeAttr('disabled'); // let the user write another message
addMessage(json.data.author, json.data.text,
json.data.color, new Date(json.data.time));
} else {
console.log('Hmm..., I\'ve never seen JSON like this: ', json);
}
};
 
/**
* Send mesage when user presses Enter key
*/
input.keydown(function(e) {
if (e.keyCode === 13) {
var msg = $(this).val();
if (!msg) {
return;
}
// send the message as an ordinary text
connection.send(msg);
$(this).val('');
// disable the input field to make the user wait until server
// sends back response
input.attr('disabled', 'disabled');
 
// we know that the first message sent from a user their name
if (myName === false) {
myName = msg;
}
}
});
 
/**
* This method is optional. If the server wasn't able to respond to the
* in 3 seconds then show some error message to notify the user that
* something is wrong.
*/
setInterval(function() {
if (connection.readyState !== 1) {
status.text('Error');
input.attr('disabled', 'disabled').val('Unable to comminucate '
+ 'with the WebSocket server.');
}
}, 3000);
 
/**
* Add message to the chat window
*/
function addMessage(author, message, color, dt) {
content.prepend('<p><span style="color:' + color + '">' + author + '</span> @ ' +
+ (dt.getHours() < 10 ? '0' + dt.getHours() : dt.getHours()) + ':'
+ (dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes())
+ ': ' + message + '</p>');
}
});
view raw chat-frontend.js hosted with ❤ by GitHub
Again I tried to put comments where it's appropriate, but I think it's still very simple.

Running the server

I wrote and tested the server on node.js v0.4.10 and v0.5.9 but I think I'm not using any special functions so it should run on older and newer version without any problem. If you're using Windows node.js > 0.5.x comes with Windows executable. I tested it on Windows as well.
So under Unix, Windows or whatever:
node chat-server.js
and you should see something like this
Thu Oct 20 2011 09:15:44 GMT+0200 (CEST) Server is listening on port 1337
Now you can open chat.html and if everything's fine it should ask you for your name and the server should write to the console:
Thu Oct 20 2011 09:27:21 GMT+0200 (CEST) Connection from origin null.
Thu Oct 20 2011 09:27:21 GMT+0200 (CEST) Connection accepted. Currently 1 client.

So what's next?

That's actually all. I'm adding a few notes at the end just to make some things a little bit more obvious.

Pros and cons of node.js

For this purpose is node.js ideal tool because:
  • It's event driven. Together with closures it's very simple to imagine the client lifecycle.
  • You don't have to care about threads, locks and all the parallel stuff.
  • It's very fast (built on V8 JavaScript Engine)
  • For games you can write the game logic just once and then use it for both server and frontend.
  • It's just like any other JavaScript.
but on the other hand there are some gotchas:
  • It's under rapid development and your server might not be compatible with newer versions of node.js.
  • It's all quiet new. I haven't seen any real application of node.js. Just a bunch of games and some nice demos.
  • Node.js unlike Apache doesn't use processes for each connection.
The last point has some important consequences. Look at the server source code where I'm declaring colors variable. I hard coded 7 colors but what if there were 7 active connections and 8th client tried to connect? Well, this would probably threw an exception and the server would broke down immediately.
The problem is that Apache runs separate process for each request and if you have a bug in your code it brakes just one process and doesn't influence the rest. Of course, creating new processes for each client is much better in terms of stability but it generates some overhead.
I like talk HTML5 Games with Rob Hawkes of Mozilla where Rob Hawkes mentions that he used monit to observe if the server is running and eventually start it again in the case it broke.

What about socket.io?

Socket.io is an interesting project (it's a module for node.js) implementing WebSocket backend and frontend with many fallbacks for probably every possible browser you can imagine. So I should probably explain why I'm not using it.
The first reason is that I think it's always better to try to write it by yourself first because then you have much better insight what's going on and when it doesn't work you can easily figure out why.
The second reason is that I want to try to write some simple games using WebSocket. Therefore all the fallbacks provided by socket.io are useless because I need as low latency as it's possible. Also, there is some magic /socket.io/socket.io.js which is probably generated according to your browser's capabilities but I'm rather trying to avoid debuging javascripts for IE6 :).
I thing socket.io is great, but it would be very unpleasant if I spent month of writing a game and then realised that socket.io generates so much overhead so it's useless and I had to rewrite it.
Anyway, for other applications (like this chat for instance) socket.io would be ideal, because ±100ms is absolutely irrelevant and this chat would work on all browser and not just Chrome 14+ and Firefox 7+.

What if I want some usage statistics?

I think good questions is how can I dig some information from the WebSocket server like number of active connections or number sent messages?
As I mentioned at the beginning is tied to HTTP server. At this moment it comes handy because we can run on the same port WebSocket server and also HTTP server.
So let's say, we want to be able to ask the server for number of current connections and number of all sent messages. For this purpose we have to create simple HTTP server that knows just one URL (/status) and sends JSON with these two numbers as a response.
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
/** ... */

/**
 * HTTP server
 */
var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' HTTP server. URL' + request.url + ' requested.');

    if (request.url === '/status') {
        response.writeHead(200, {'Content-Type': 'application/json'});
        var responseObject = {
            currentClients: clients.length,
            totalHistory: history.length
        }
        response.end(JSON.stringify(responseObject));
    } else {
        response.writeHead(404, {'Content-Type': 'text/plain'});
        response.end('Sorry, unknown url');
    }
});
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});

/** ... */
Now when you access http://localhost:1337/status you should see something similar to:
{"url":"/status","response":{"currentClients":2,"totalClients":4,"totalHistory":6}}
Clients and history are two global variables (I know, bad practise) that I'm using for different purpose but in this situation I can reuse them easily without modifying rest of the server.

Running under Windows

As I menioned above you can run this chat on Windows too.
There have been a couple of changes in the websocket module and now for Windows you have to follow some extra steps.
Probably the only problem might be with npm (Node Package Manager). To be honest I'm usually avoiding npm because for me it's easier to just download particular module and place it in node_modules directory (that's where node.js searches for modules by default).
In other words to run this chat tutorial without npm download websocket module from github, unpack it, and rename the directory to websocket. Then place it in node_modules directory for example like this:
node/
node/node.exe
node/examples/
node/examples/chat.html
node/examples/chat.js
node/examples/server.js
node/examples/frontend.js
node/node_modules/
node/node_modules/websocket
node/node_modules/websocket/...
node/node_modules/websocket/...
...

Download

download full source code (html, frontend, server) for this tutorial.
I put all source codes on GitHub, so feel free to modify whatever you want.

Conclusion

That's all for this tutorial. I would be really glad if you could post to comment some examples of WebSocket usage that you liked (it doesn't have to be built on node.js).

Resources


Hay otro demo para socket echo:


viernes, 22 de mayo de 2015

Empresas "Contrata-Latinos" por favor basta de hipocresía, si?

Señor CEO, CTO o quien sea de una de estas
empresas vendedoras de carne para el extranjero:

A quién corresponda

Ya es un descaro la forma que tratan de contratarme para que ustedes les puedan vender mano de obra barata al mercado norteamericano o europeo.

Todos los días (promedio) recibo una oferta de ustedes, que dice más o menos:
"Empresa de renombre busca desarrollador Android para imporante cliente en USA"
Y la verdad es que me tienen cansado. No voy a nombrar la última empresa que me trató de llevar hoy para sus filas porque no puedo poner las pruebas en esta carta y por ende, nombrarla sería como usar una prueba circunstancial en un juicio.

Pero resulta que el tema es así: Yo ahora estoy trabajando bajo relación de dependencia (o sea que tengo un recibo de sueldo y todas las prestaciones y encima hago mi trabajo desde la comodidad de mi home-office) Gracias a la confianza que he logrado implementar debido a mi conocimiento, he podido lograr también una paga de dinero considerable, fuera de la escala de mercado... Y entonces es ahí cuando aparece de la nada esta empresa y me ofrece (supuestamente) algo imperdible: Sumarme a su próximo proyecto bajo las siguientes condiciones:

a) Tengo que pasar por enormidad de entrevistas.

b) Cuando les dije el salario que tienen que superar (o al menos igualar), como que se quedó medio sin palabras la entrevistadora.

c) Yo no pasaría a ser empleado de ellos sino que les tendría que generar un recibo (factura) por mis servicios.

En fin, nada de esto es beneficioso para mi. Al contrario, todo es para ellos (porque encima estoy seguro que voy a tener que demostrar con creces que soy merecedor de semejante diner que pido)

Entonces le digo: Paren con este juego si no están dispuestos a pagar o si no están dispuestos a confiar en la gente. Yo soy un programador que lleva más de diez años haciendo todo lo que hay que hacer. Y como yo hay muchos otros más. Si ustedes nos llaman, entonces de verdad tienen que darnos beneficios económicos.

Porque tomarnos una prueba técnica o de algoritmos estúpidos a esta altura es como tomarnos el pelo. Mejor nos dan un trabajo de prueba y se lo resolvemos sin problemas. Pero no nos pregunten sobre un algoritmo que en tu puta vida se va a implementar en alguno de tus proyectos.

Si estamos ganando un dinero que ustedes no pueden pagar, no sean negreros y no traten de hacernos sentir mal por ganar tanto y "ustedes tan poco". Si no lo pueden pagar o superar, no nos llamen.

Si estamos en relación de dependencia y ustedes quieren que cambiemos por algo tan ilegal como es el hecho de ser un empleado encubierto, mediante la facturación mensual que les tengo que hacer, ni se molesten en hacerme perder el tiempo.

Con todo mi amor,
Walter.

viernes, 27 de febrero de 2015

Android very low level - One post, all the info!

I found this post which is very useful for low-level android developers. You have here how to remove and change all you want from the system APKs in Android core.

http://forum.xda-developers.com/showthread.php?t=2799050


sábado, 10 de enero de 2015

Apple en problemas

Lo vengo diciendo desde que falleció el querido ex-co-fundador de Apple. Y es que lo único que le espera es un camino hacia abajo.

Ya se que en ventas van geniales y todo eso, pero el mundo avanza con nuevas ideas y Apple lo que está haciendo el copìar un poco todo lo que ve. Y así no es como se hace el dinero que lo mantiene a Apple donde una vez estuvo.

Ya le pasó a BlackBerry, lo pasaron literalmente por arriba y no se pudo recomponer...

Pero bien, la noticia que recibo hoy es sobre el post de uno de los mejores desarrolladores que tiene Apple (Marco Arment) y co-fundador de otros emprendimientos muy populares (a mi gusto son una estupidez, pero que se le va a hacer, es lo más usado en el mundo) Y estoy hablando de  Tumblr, Instapaper y Overcast.

Se queja de la mala calidad del software que produce Apple cada año. Dice literalmente que es mejor tener un software de calidad para después recién preocuparse por agregar features. Y Apple hace todo lo contrario.

Quien sea desarrollador (como yo) entenderá que ésto es lo que se le pide a toda empresa. Y, cuando no lo cumplen, uno siente que está poniendo en juego su reputación, porque todo el mundo comenta sobre lo malo que es el software producido y luego comentarán cosas como: "Quién hace ese software tan malo? Y, lo hace este muchacho Marco Arment"

Lo más gracioso es que en su blog, Marco Arment ya tuvo de retractarse de haber escrito lo que escribió y se asombra de ser tan sorprendentemente popular por un día.

Es gracioso que inclusive linkea a una historia de otra persona y esa persona (por miedo o vaya a saber por qué) retiró el posteo! Muy gracioso todo...

Les dejo sus palabras aquí porque en unos días ya ni siquiera tal vez exista el post:

Apple’s hardware today is amazing — it has never been better. But the software quality has fallen so much in the last few years that I’m deeply concerned for its future. I’m typing this on a computer whose existence I didn’t even think would be possible yet, but it runs an OS with embarrassing bugs and fundamental regressions. Just a few years ago, we would have relentlessly made fun of Windows users for these same bugs on their inferior OS, but we can’t talk anymore.
“It just works” was never completely true, but I don’t think the list of qualifiers and asterisks has ever been longer. We now need to treat Apple’s OS and application releases with the same extreme skepticism and trepidation that conservative Windows IT departments employ.
Geoff Wozniak went back to desktop Linux after almost a decade on OS X(Update: He appears to have taken the post down). It’s just one person’s story, but many of his cited reasons resonate widely. I suspect the biggest force keeping stories like this from being more common is that Windows is still worse overall and desktop Linux is still too much of a pain in the ass for most people. But it should be troubling if a lot of people are staying on your OS because everything else is worse, not necessarily because they love it.
Apple has always been a marketing-driven company, but there’s a balance to be struck. Marketing plays a vital role, but marketing priorities cannot come at significant expense to quality.
I suspect the rapid decline of Apple’s software is a sign that marketing1 istoo high a priority at Apple today: having major new releases every year is clearly impossible for the engineering teams to keep up with while maintaining quality. Maybe it’s an engineering problem, but I suspect not — I doubt that any cohesive engineering team could keep up with these demands and maintain significantly higher quality.2
The problem seems to be quite simple: they’re doing too much, with unrealistic deadlines.
We don’t need major OS releases every year. We don’t need each OS release to have a huge list of new features. We need our computers, phones, and tablets to work well first so we can enjoy new features released at a healthy, gradual, sustainable pace.
I fear that Apple’s leadership doesn’t realize quite how badly and deeply their software flaws have damaged their reputation, because if they realized it, they’d make serious changes that don’t appear to be happening. Instead, the opposite appears to be happening: the pace of rapid updates on multiple product lines seems to be expanding and accelerating.

Este es el update pidiendo perdón (o algo así)

Last night, I wrote a quick post about Apple’s software quality. Originally, it was just a link to the Linux post. I had too much commentary, so at the last minute, I changed it to an article and came up with a quick headline. I’d been toying with the idea of the “moral high ground”, but that was too harsh and incorrect, so I went with the “functional high ground”, thinking almost nobody would get the reference and it would uneventfully breeze through my geek friends’ RSS readers like most of my posts.
This morning, my words were everywhere, chopped up and twisted by sensational opportunists to fuel the tired “Apple is doomed!” narrative with my name on them. (Or Tumblr’s name, which was even worse.) Business Insider started the party, as usual, but it spread like wildfire from there. Huffington Post. Wall Street Journal. CNN. Heise. Even a televised CNBC discussion segment.
All of them using my name, and a few of my words, to create drama, fan the flames, and get some views.
And there were a lot of views. The small fraction that came back to my site still pushed it past the pageview totals for any posts I wrote in 2014. You might think this is a dream come true for a blogger, but it’s horrible.
Instead, I looked back at what I wrote with regret, guilt, and embarrassment. The sensationalism was my fault — I started it with the headline and many poor word choices, which were overly harsh and extreme. I was being much nastier and more alarmist than I intended. I edited some words to be more fair and accurate, but it was too late. I can’t blame the opportunists for taking the bait that I hastily left for them.1
Most of my posts go effectively nowhere, but occasionally, one will unexpectedly go really far — and this blew past everything I’ve ever done. When that happens, there’s no chance to revise, no room for error, and no way to stop it.
If there’s any flaw, it’s an unstoppable nightmare of embarrassment and guilt. Most people, myself included, aren’t accustomed to that level of scrutiny. Those who are usually have PR training, editors, and handlers to protect them from publishing flippant blog posts before they go to bed.
Instead of what was intended to be constructive criticism of the most influential company in my life, I handed the press more poorly written fuel to hamfistedly stab Apple with my name and reputation behind it. And my name will be on that forever.
Had I known that it would go as far as it did, I never would have written it.
I now need to write everything with the fear that any hastily written article might end up on TV, with the most extreme word in the article singled out with my name on it forever.
I’ll keep writing — I can’t stay away. But academically, it’s not worth the risk.

Y les dejo esta nota relacionada donde un conocido investigador de seguridad habla de lo inseguro que es Apple en estos días.

"Apple es tan inseguro como Windows"
http://www.elladodelmal.com/2015/01/protege-tu-iphone-es-tan-inseguro-como.html