GitHub e Two Factor Authentication no Visual Studio

5/3/2015 4:12:13 PM By Felipe Pessoto

Se você ainda não está usando o Visual Studio 2015 RC, que vem com uma extensão do GitHub, vai ter problemas ao sincronizar seu repositório com o GitHub após ativar o Two Factor Authentication.

Para quem ainda não viu a nova extensão pro VS2015:

Atualmente, quem usa o VS2013, vai se deparar um com erro 401, e a tela de login.

Clique em Sync

Será exibida a tela de login.

Não adianta colocar seu login e senha. Pois agora o Two Factor Authentication está ativo.

Como o Visual Studio não suporta essa funcionalidade, você vai precisar criar um Token no site do GitHub. O que é bem simples, acesse o link https://github.com/settings/tokens e clique em "Generate new token"

As opções padrões são suficientes:

Guarde o token gerado

Ele deve ser usado no login do login, a senha deve ficar em branco:

Com isso você vai conseguir sincronizar com sucesso:

 

Desenvolva como se o próximo a manter seu código seja um maníaco homicida que sabe onde você mora.

8/22/2014 10:02:47 PM By Felipe Pessoto

Normalmente quando estou programando não estou pensando em fazer funcionar apenas, na verdade o desafio é fazer de forma simples e óbvia. O fazer funcionar é o mínimo, se não funciona não adianta criar.

As vezes, ou muitas vezes, o dificil é fazer o simples, pode ser porquê não conhecemos a forma certa ou como usar determinado Framework, por estar "dentro" do problema e já influenciado pelo código existente ou mesmo pelo entusiamo de criar códigos mirabolantes.

"Code as if the next guy to maintain your code is a homicidal maniac who knows where you live." -Kathy Sierra and Bert Bates

Criando código bem estruturado, vai poupar seus colegas de muitos problemas (bugs) e economizar tempo sempre que precisar mexer no seu código. Costumo dizer que a próxima pessoa a mexer no código pode ser eu mesmo daqui 6 meses, quando já não lembro muita coisa do projeto, e ter o código limpo acaba sendo uma recompensa.

Para ter código limpo você depende de muitas coisas, mas é muito mais fácil faze-las quando está escrevendo pela primeira vez do que no futuro ter que entender o motivo de tudo que foi feito do jeito que está. Algumas coisas como:

  • Usar uma variavel entre alguns calculos, com um nome descritivo
  • Separar o código em método que façam sentido, normalmente com altura menor que sua tela.
  • Agrupar chamadas em blocos onde o código esteja relacionado de alguma forma e deixando uma linha em branco antes do próximo. Meio que para separar os pensamentos
  • Manter os métodos em ordem de chamadas, por exemplo se tenho um método que chama outros dois método na mesma classe, mantenho eles perto, o chamador primeiro, depois os chamados.
  • Não duplicar código.
  • Não depender de efeitos colaterais, ou regras "fracas".
  • Entre muitos outros. Recomendo o livro Clean Code: A Handbook of Agile Software Craftsmanship

 Outro fato que muita gente ignora é a compilação e deploy. Uma das coisas que dão mais trabalho e medo, é pegar um código muito antigo que muitas vezes nem compila e ter que só alterar uma linha de código. Como garantir que a versão do código que tenho é a que foi pra produção a dois anos atras? E se esse código está com alterarações que nunca subiram pra produção?

E o mais importante, refatorar, refatorar e refatorar. Antes e depois de mexer em algum código, veja as opotunidades de refatorar.

Quando pegar um código muito bagunçado, faça uma limpeza, remova duplicidades, garanta que tudo ainda funciona e então faça suas alterações. E ao terminar garanta que as alterações estão organizadas, entre um teste e outro acabamos deixando coisas para trás.

 A biblioteca que uso pra cache, Fujiy Util, é um bom exemplo de refatoração, apesar de ser pequena, a principio era um só método que fazia tudo, agora tenho classes separadas pra gerar chaves a partir de uma chamada de método e a classe que gerencia o Cache em si.

.NET Transactional File Manager

10/1/2013 9:00:00 PM By Felipe Pessoto

Estamos acostumados a usar transações sempre que trabalhamos com banco de dados, mesmo pra quem usa um ORM como o Entity Framework, que cria as transações implicitamente. Isso tudo pra garantir que nossas alterações sejam atomicas, evitando pedidos de compra sem itens, um débito sem um crédito, um pagamento de salário sem marcá-lo como pago, etc.

Esse processo fica mais complicado quando temos arquivos em disco envolvidos, por exemplo, um processo onde se insere uma linha no banco e move um arquivo, principalmente dentro de um laço. Se ocorrer uma exception de disco cheio no 10º arquivo, como fazer pra voltar os 9 anteriores ao local original? Tratar manualmente não parece muito confiável e limpo.

Pra estes casos existe uma biblioteca chamada .NET Transactional File Manager, é bem simples e funciona praticamente sem overhead, implementando a interface IEnlistmentNotification, permitindo participar de uma transação do System.Transactions.Transaction.

A biblioteca não usa o Transactional NTFS, o que permite o uso no Windows XP e Windows Server 2003, por isso também não faz uso do DTC.

Então a biblioteca não é confiavel? Depende! Da maneira que ela funciona não vai garantir o Rollback em caso de falha de hardware ou se o processo for finalizado, ela funciona automatizando o que teriamos que tratar manualmente se a transação for cancelada, movendo de volta os arquivos, apagando o que foi copiado ou criado, etc. No meu caso é o suficiente. Se for necessário usar Transactional NTFS existe a biblioteca AlphaFS.

A utilização é muito simples, parecido com a classe File, só não é static, não sei o motivo.

new TxFileManager().Move(fonte, destino);

.NET Transactional File Manager no Codeplex

.NET Transactional File Manager no NuGet

A diferença que o C# 5.0 faz com o async/await

3/11/2013 8:51:00 PM By Felipe Pessoto

A melhor forma de ver a grande diferença que o async faz é usando exemplos. Saindo de um código não só maior, mas muito mais complicado, com callbacks, tratamento de contexto e thread de execução, tratamento de erros aninhados com os callbacks, pra um código simples, como se fosse um código síncrono comum.

Código Antigo:

void ShowStuff ()
{
	var client = new WebClient ();
	var content = JsonValue.Parse (client.DownloadString ("http://api.worldbank.org/countries?format=json&per_page=50"));
	int number_of_countries = content [0] ["total"];
	int done = 0, error = 0;

	InvokeOnMainThread (() => {
		CountriesLabel.Text = string.Format ("Countries: {0} done: 0 error: 0", number_of_countries);
	});

	foreach (JsonObject c in content [1]) {
		string country_url = string.Format ("http://api.worldbank.org/countries/{0}/indicators/NY.GDP.MKTP.CD&format=json", (string)c ["id"]);
		JsonValue json = null;

		try {
			json = JsonValue.Parse (client.DownloadString (country_url));
		} catch (Exception e){
			++error;
			InvokeOnMainThread (()=> status.Text = "Got exception "+ e);
			continue;
		}

		ThreadPool.QueueUserWorkItem (delegate {
			Map map = null;
			try {
				map = LoadCountryLogo (c ["name"]).Result;
			} catch (Exception e){
				++error;
				InvokeOnMainThread (()=> status.Text = "Got exception "+ e);
			}
			if (map != null){
				ThreadPool.QueueUserWorkItem (delegate {
					Position position = null;

					try {
						position = LookupCountryPosition (c ["longitude"], c ["latitude"]).Result;
						if (position != null)
							InvokeOnMainThread (() => {
								AddPin (map, position); 
								++done;
								status.Text = json ["name"];

							});
					} catch (Exception e){
						error++;
						InvokeOnMainThread (()=> status.Text = "Got exception "+ e);
					}

				});
			}
		});
		
		InvokeOnMainThread (() => CountriesLabel.Text = string.Format ("Countries: {0} done: {1} error: {2}", number_of_countries, done, error));
	}
	InvokeOnMainThread (() => {
		CountriesLabel.Text = string.Format ("Countries: {0}", number_of_countries);
	});
}
 

Código usando C# 5.0:

async Task ShowStuffAsync ()
{
	var client = new HttpClient ();

	var content = JsonValue.Parse (await client.GetStringAsync ("http://api.worldbank.org/countries?format=json"));
	int number_of_countries = content [0] ["per_page"];
	int done = 0, error = 0;

	CountriesLabel.Text = string.Format ("Countries: {0} done: 0 error: 0", number_of_countries);

	foreach (JsonObject c in content [1]) {
		try {
			string country_url = string.Format ("http://api.worldbank.org/countries/{0}/indicators/NY.GDP.MKTP.CD&format=json", (string)c ["id"]);
			var json = JsonValue.Parse (await client.GetStringAsync (country_url));
			var map = await LoadCountryLogoAsync (json ["name"]);
			if (map != null){
				var position = await LookupCountryPositionAsync (c ["longitude"], c ["latitude"]);
				if (position != null){
					AddPin (map, position);
					status.Text = json ["name"];
					++done;
				}
			}

		} catch (Exception e) {
			++error;
			status.Text = "Got exception "+ e;
		}
		CountriesLabel.Text = string.Format ("Countries: {0} done: {1} error: {2}", number_of_countries, done, error);
	}
	CountriesLabel.Text = string.Format ("Countries: {0}", number_of_countries);
}