Table of contents

    Integração dos Fontes Abertos do .NET

    Com a recente liberação de partes do código do .NET, nós queremos trazer os melhores pedaços do .NET para o Mono, e contribuir os componentes multi-plataforma do Mono para os esforços do .NET.

    Este documento descreve as estratégias que nos utilizaremos.

    Nós estaremos acompanhando os esforços no Trello

    Contexto

    A Microsoft está abrindo o .NET em duas formas:

    • .NET Core: é uma versão re-imaginada do .NET que é capaz de ser instalada integrada a aplicações web e fortemente focada em um novo conjunto de assemblies e APIs baseada no perfil PCL 2.0. É um projeto completamente open source, com a Microsoft aceitando contribuições e desenvolvendo de forma aberta.

    • Partes do Framework .NET: são partes do framework .NET que vem com o Windows, e a API que o Mono vem implementado ao longo de anos. A versão publicada é um instantâneo do fonte do Framework .NET. Embora a Microsoft esteja publicando o código fonte, eles não estão ativamente desenvolvendo esta árvore em aberto, nem aceitando correções.

    Considerações

    Esta seção lista os cuidados que devemos ter em mente ao incorporar código fonte do .NET dentro do Mono, e que não podemos esquecer ao aprimorar o código.

    Os itens listados abaixo identificam as restrições que temos ao incorporar essa massa de código.

    Código Específico de Plataforma do Mono

    Em muitos casos, o Mono contem código específico de plataforma que atualmente inexiste no .NET. Existe uma grande variedade de funcionalidades desse tipo.
    Alguns exemplos:

    • A classe System.Environment que provê um conjunto de locais específicos por plataforma para as aplicações procurarem certos ‘locais bem conhecidos’ no sistema de arquivos.

    • A classe Registry que provê uma abstração que mapeia para as APIs do Windows ou uma implementação baseada em arquivos no Unix.

    Classes do Mono com Integração Estreita com o Ambiente de Execução

    Algumas APIs do framework .NET tem extreita dependência com a implementação do ambiente de execução. E esse também é o caso da implementação do Mono.

    Há casos em que teremos um desafio extra pela frente para fazer a integração com o ambiente de execução funcionar (por exemplo, chavear nosso pobre suporte ao tipo decimal pela versão da Microsoft seria decididamente um ganho). Em outros casos, o tamanho da tarefa não vale o esforço, como o suporte a System.Reflection.Emit.

    Perfis do Mono

    O Mono disponibiliza um perfil de API Mobile projetado para expor uma API mais leve para utilização em dispositivos móveis, consoles de jogos e no projeto Mono for Unreal Engine.

    O Perfil Mobile basicamente remove do sistema algumas da dependências .NET mais pesadas. Ele principalmente lida com remover dependências a System.Configuration das nossas bibliotecas de classes.

    Mono Core

    No longo prazo, nós queremos adotar uma estratégia similar ao do .NET Core, onde nós teremos uma camada fina de APIs específicas da plataforma/VM, e permitiremos aos nossos usuários usar o Mono na mesma forma que o .NET core pode ser usado, sem grandes bibliotecas/perfis.

    As Classes do Mono são Amigáveis ao Linker

    Algumas das bibliotecas de classe do Mono foram projetadas para manter o seu resultado amigável ao linker, um pedaço importante da funcionalidade requerida pelas nossas implementações para Android e iOS.

    Isto é feito substituindo algumas associações ‘fracas’, manifestas só em tempo de execução, por associações fortes, ou ensinando nosso linker sobre as bibliotecas e as conexões entre certas classes e suas exigências. Muitos dessas ligações provavelmente existem no .NET também, mas nós precisamos assegurar que não haja regressões ao incorporar código do .NET.

    Bootstrapping das Bibliotecas Básicas

    O bootstrapping das bibliotecas fundamentais não é uma coisa divertida. A Microsoft incluiu dependências cíclicas em vários grupos de bibliotecas. Por exemplo, mscorlib, System, System.Xml, System.Configuration e System.Core são compiladas referenciando os tipos umas das outras. Outro emaranhado existe na família System.Web.

    O Mono atualmente tem um processo de compilação em múltiplos estágios para criar essas bibliotecas que tem dependência cíclica. Trazer novo código da Microsoft é possível, mas a cada classe que for incorporada, podemos ter que ajustar o processo de compilação.

    ‘Recursos’ Faltantes

    O fonte liberado pela Microsoft não incluem os recursos (resources) exigidos por parte do código. Isto se manifesta com referências a uma classe chamada “SR”.

    Nós teremos que autogerá-los.

    Mão de Obra Escassa

    Nós temos escassez de mão de obra, então ao trazer código do .NET, nós temos que escolher nossas batalhas.

    Os pedaços do Mono que tem sido bastantes utilizados são de uma melhor qualidade do que os pedaços não muito utilizados, ou que estão a muito tempo sem manutenção.

    É melhor focar os nossos esforços nos alvos que possam trazer-nos alto-valor nas bibliotecas de classe do .NET do que trazer coisas que funcionam bem no Mono e estão bem testadas.

    Código .NET Incompleto

    Parte do código .NET que está sendo disponibilizado pode não estar completo, podem estar faltando resources, strings, scripts de compilação e pode não ser trivialmente compilável.
    Portanto é importante que ao submeter um pull request, a alteração compile completamente.

    Efeitos Colaterais na Performance/Uso de Memória

    Este é provavelmente um problema inexistente, mas nós podemos achar casos em que as bibliotecas de classes do Mono foram otimizadas para uso no ambiente de execução do Mono de tal forma que incorporar o código equivalente da Microsoft pode regredir a performance ou causar a alocação de mais memória.

    Alguns casos para ficar de olho:

    • Checagens do Code Access Security: estas provavelmente estão presentes no código do .NET, e elas essencialmente não existem no Mono. São relativamente custosas para executar, e o Mono não chegou a implementá-las corretamente. Então nós teriamos que colocar um monte de ifdefs ao importar todo código relacionado ao suporte ao CAS.

    • *Descarte de Objetos: O Mono nem sempre implementou fielmente o padrão de descarte de objetos (Dispose). É um padrão em que objetos que implementam a interface IDisposable arremessam um exceção do tipo ObjectDisposedException sempre que o método Dispose já foi chamado, mas um membro dessa instância é executado. Isto requer mais código condicional que o Mono não tem em alguns lugares. Pode ser que não seja importante, mas devemos prestar alguma atenção a isso.

    • Validação de Enumerações: O .NET tende a validar os valores de enumerações passados a suas funções. O Mono não faz isso, portanto podemos ter um impacto na performance ao importar esse tipo de código.

    As checagens de Code Access Security são provavelmente o que mais nós devemos nos preocupar em filtrar, por serem completamente inúteis no Mono.

    Definiçoes de Tempo de Compilação

    O código fonte da Microsoft contém muitos tipos diferentes de definições de tempo de compilação (defines) que são usados para compilação condicional. Sempre que importarmos algum código da Microsoft, nós temos que fazer uma auditoria e determinar que funcionalidades são necessárias.

    Estratégia

    Em geral, nós estaremos integrando código que vem do Fonte de Referência liberado, porque este contem a API que é mais próxima da do Mono.

    Nós estaremos acompanhando a atribuição de tarefas no Trello.

    Mais tarde, quando implementarmos o Mono Core, nós inversamente contribuiremos bits específicos a VM/SO para o .NET Core.

    Nós temos que bolar um plano de integração que maximize os benefícios ao Mono e nossos usuários com o mínimo de esforço de engenharia. Embora em um mundo ideal nós pudessemos trazer até 80-90% do código, seria um esforço imenso com muitos riscos envolvidos. Nós iremos priorizar o trabalho para focar naquilo que traga os maiores benefícios de cara para a comunidade Mono, e deixar os pedaços mais complicados/intensivos para depois.

    Dando um grande impulso ao Mono desde o começo

    Ao trazer código para o Mono, nós podemos fazê-lo das seguintes formas:

    • Assemblies inteiros
    • Classes inteiras
    • Trabalho misto
    • Membros individuais

    Assemblies Inteiros

    Nós podemos portar assemblies inteiros quando nosso assembly é reconhecido como sendo muito cheio de bugs, em má forma, ou completamente quebrado.

    Candidatos imediatos para isto incluem:

    • WCF - quase que imediatamente
    • System.Web - quase que imediatamente

    Candidatos de médio prazo incluem:

    • System.Configuration - possível, mas requer cuidadosa verificação
    • System.Linq.Data
    • Remoting

    Candidatos de longo prazo incluem:

    • A pilha XML

    Classes Inteiras

    Nós portaremos classes inteiras quando a classe ou família de classes é reconhecida como sendo muito cheia de bugs no Mono, mal conservada ou como uma fonte de problemas. Candidatos incluem:

    • System.Text.RegularExpressions

    Trabalho Misto

    São bibliotecas que tem código de alta qualidade e que as contrapartes no Mono podem ter limitações, bugs ou problemas. Mas a implementação da Microsoft contem dependências a bibliotecas nativas que não existem em todas as plataformas. Possíveis candidatos:

    • Pilha cliente de HTTP
    • System.Data.* - A implementação da Microsoft tem muitas dependências a código nativo que tem que ser refatoradas para suportar múltiplas plataformas.

    Membros Individuais

    Nós encontraremos esse tipo de código em alguns lugares. Existem lugares no Mono que embora bons de forma geral, podem ter bugs conhecidos e limitações. A funcionalidade de binding em System.Reflection é um exemplo de um método que funciona, mas que pode ter bugs e erros nas ‘bordas’.

    Porte e Regressões

    Sempre que trouxermos código .NET para substituir código do Mono, pode haver casos em que será introduzida uma regressão de algum tipo: funcionalidade, performance ou trazemos um comportamento que é incompatível com o uso idiomático que os usuários do Mono estão acostumados a muito tempo.

    Em geral, quando portando código para o Mono, nós devemos garantir que a suite de testes do Mono continue a passar sem problemas, e que nenhuma regressão seja introduzida. Se uma regressão for introduzida, nós temos que registrar o bug e atuar na busca da solução do problema específico.

    abdedc04bb366fb61a02a32b388f497cd91a75e8

    APIs muito populares, majoritariamente livres de bugs: pule

    O núcleo do Mono está em muito boa forma, e muito pouco valor pode ser agregado trazendo a implementação do .NET nesses pedaços. Consumiria um valioso tempo de engenharia para substituir código bom por outro pedaço de código bom, ao mesmo tempo que estariamos pagando o preço de regressões em potencial.

    Capacitando Terceiros

    Existem certos pedaços de código que serão difíceis de processar, mas que se o fizermos, poderemos ajudar o esforço de terceiros que não conhecem as internalidades do Mono ou nosso processo de compilação para contribuirem.

    Lidando com System.Configuration

    Em geral, o processo a seguir ao portar código que envolve o System.Configuration que nós queremos que funcione no perfil completo e no perfil Mobile é aproximadamente:

    • Comentar fora a classe pública derivada de ConfigurationSection.
    • Manter a classe SettingsSectionInternal, pois muito código depende dela.
    • Usar ifdef para excluir o construtor que depende em System.Configuration dessa classe que usa System.Configuration, e substituir por valores fixos obtidos ao rodar o código no .NET (valores default).
    • Adicionar o modificador partial na classe SettingsSectionInternal.
    • Prover um construtor na classe parcial do Mono para inserir os valores default.
    • Monitorar cada setting, para depois decidirmos se queremos prover uma API C# para mudar esses valores.

    Estilo do Código Fonte

    Ao fazer mudanças, tente manter o estilo do projeto original. Se está mudando o código do .NET, use o estilo deles. Quando fazendo mudanças no Mono, use o nosso estilo.

    Nós acreditamos que poderemos fazer poucas mudanças no código de origem e basicamente usar ou blocos #if, classes partial e dividir algumas coisas para alcançar a portabilidade.

    .NET Core e o Mono

    Nós queremos contribuir parte do código multi-plataforma do Mono, bem como trechos que nós portarmos do código de referência do Framework .NET ao esforço do .NET Core.

    Nós atualizaremos esta página com mais informação conforme o processo de porte de código da Microsoft evolua e nós contribuamos algo do nosso código ou do deles para o esforço.