Arda Çetinkaya Yazılım ve arada kendim ile ilgili karaladıklarım…

Geliştirdiğimiz uygulamaların durumlarını kontrol eden, bu kontrollere göre çeşitli alarmlar üreten monitör araçları eminim bir çoğumuza tanıdık gelecektir. Uygulamaların belli durumlarına göre tedbirler alıp, bu durumlarda müdahale edip gerekli düzenlemeleri yapabilmek adına uygulama monitör araçları ve yöntemleri oldukça önemli bir konu. Dağıtık bir yapıya sahip uygulamalarda ise olmazsa olmaz; hatta bence uygulamanın sağlığı için zorunlu bir yaklaşım. ASP.NET Core tarafında bu tarz ihtiyaçları nasıl gerçekleştirebiliriz buna bakalım…

Ama önce kavramı ve konuyu daha iyi anlamak için, bir çoğumuza tanıdık gelebilecek bir senaryoyu hatırlayalım. Bir web uygulamasının monitör edilmesini sağlamak için http://minepla.net/Status.aspx tarzı bir sayfa(url) geliştirdiğimizi düşünelim; hatta uygulamanın içinde belki bir web servis. Bu URL’de basit belli işlemler gerçekleştirerek uygulamanın durumu hakkında monitör araçlarına çeşitli bilgiler paslayabiliriz. Bu sayfaya erişim olmazsa, sayfanın yüklenmesi uzun sürerse, veri tabanı işlemlerinde yavaşlık, sayfanın içinde basit bir iş kuralından beklenen sonuç dönmezse gibi gibi farklı durumları, ilgili sistemlere iletip alarm yaratılmasını sağlayabiliyoruz. Piyasadaki bir çok monitör araçının bu tarz kaynaklardan alarm üretmesi standart artık…

ASP.NET Core tarafında, monitör araçlarının bu tarz ihtiyaçları için v2.2 Preview 2 ile gelen HealthChecks kavramına bir bakalım hızlıca.

HealthChecks kavramı ASP.NET Core’un önceki versiyonları için de bir şekilde vardı. Ama Preview 2’deki son durumundan farklı ve ek paketler ile kullanılıyordu. Şimdi Preview olmasına rağmen direkt ASP.NET Core’un içinde ve daha olgun bir durumda.

ASP.NET Core’da artık uygulamaların sağlıkları ile ilgili çeşitli durumları paylaşmak için servis olarak çeşitli kontrolleri ekleyebiliyoruz. Bunun için ConfigureServices() metodunun içerisine aşağıdaki gibi .AddHealthChecks() şeklinde kendi ihtiyaçlarımıza göre geliştirdiğimiz servisimizi ekliyoruz. Burada ihtiyaça göre metotun diğer versiyonlarını da bir göz atın derim. Şimdi onlara çok girmeyeceğim.

        public void ConfigureServices(IServiceCollection services)
        {
            .
            ..
            ...
            ....
            
            services.AddHealthChecks()
                    .AddCheck<CustomCheck>();
            ....
            ...
            ..
            .
        }

Bununla beraber, Startup.cs içindeki Configure() methodu ile uygulamamızda da HealthCheck servisinin aktif olacağını belirtmemiz gerekiyor. Burada URL olarak path’i de belirtebiliyoruz. Bu sayede http://localhost:1234/IsHealthy şeklinde uygulamanın çeşitli durumlarını paylaşabileceğimiz URL path’ini tanımlıyoruz.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            .
            ..
            ...
            app.UseHealthChecks("/IsHealthy");
            
            ...
            ..
            .
        }

Microsoft.AspNetCore.Diagnostics.HealthChecks namespace’i ile gelen bir kaç arayüz ile kendi kontrol yöntemimizi geliştirip, uygulamamızın durumlarını kontrol edebiliyoruz.

Read More

.NET Core bir çok acıdan .NET teknolojileri ile geliştirilen sistemlere farklı yaklaşımlar katıyor. Açık kaynak geliştirme yaklaşımı, farklı platformlarda çalışabilen bir yapısının olması, performans açısından kuvvetli olması, hızlı ve sürekli olan geliştirme döngüleri gibi gibi temel bir kaç konu ve derinlerde niceleri… Bu yazıda çok derinlere inmeden, .NET Core’un performans konusundaki iyileştirmelerinden bir tanesinden bahsetmeye çalışacağım.

Şu sıralar bildiğiniz gibi .NET Core 2.2 Preview 2 yayınlandı ve RTM’e biraz daha yaklaştı. Bu versiyon ile arka tarafta oldukça önemli; performans ile alakalı, bir özellik .NET Core ile geliştirilen uygulamalara dahil oluyor. Performans tarafındaki bazı iyileştirmeler direkt geliştirme alışkanlıklarımıza dokunmasa da onların farkındalığı, uzun vadede önemli diye düşünüyorum.

Bahsedeceğim iyileştirme ya da yeni özellik, derleme tarafında olan bir yenilik. Ve aslında .NET Core 2.1 ile hayatımıza çoktan gelmişti. Ancak varsayılan özellik olarak bu özellik devreye sokulmamıştı. Sadece belli bir ayar ile aktif hale geliyordu. .NET Core 2.2 ile beraber artık varsayılan olarak, aktif bir şekilde .NET Core uygulamalarının hayatına girecek. .NET Core 2.2 Preview 2 ile de direkt artık aktif… Peki ne bu iyileştirme?

İyileştirmeden tam bahsetmeden önce, standart .NET Framework tarafındaki derleme yaklaşımını bir hatırlayalım. Bildiğiniz gibi yazmış olduğumuz C#/VB.NET/F# kodlarını derlediğimiz zaman, bu kodlar Microsoft Intermediate Language(MSIL)’e dönüşüyor ve *.dll olarak ya da *.exe olarak çalışmaya hazır bir şekilde saklanıyor. Kodlarımız çalıştığı zaman, Common Language Runtime(CLR) tarafından MSIL’e dönüşmüş kodlarımızı Just-In-Time(JIT) derleyicisi ile tekrar derleniyor ve işlemcinin(CPU) anlayacağı dile yani makine diline dönüştürüp işlemci tarafından çalıştırılmasını sağlıyor. Bu iki farklı derleme aşamasında, derleyiciler kendi çalışma durumlarına göre çeşitli optimizasyonlar yapıyor. Bu derlemeler tek bir seferde yapılıyor. Dolayısıyla yapılan optimizasyonlar tek bir seferlik oluyor. JIT derleyicisi çalışma zamanını direkt etkileyecek çıktılar ürettiği için oradaki optimizasyonlar oldukça önemli. Orada kullanılan algoritmalara göre derlenen çıktı, çok hızlı başlayabilir ama normal durağan anında farklı şekilde işleyebilir. Ya da tam tersi…Kısa bir özet olması için çok ayrıntılara girmiyor ve burada bırakıyorum, biz gelelim .NET Core 2.x tarafına…

.NET Core 2.1 ile, JIT tarafında bir çok iyileştirme yapıldı. Microsoft’un benchmark’larına göre de oldukça etkileyici çıktılara sahip iyileştirmeler. Bunlara buradan erişebilirsiniz…

.NET Core 2.2 ile hayatımıza girecek en önemli iyileştirme çalışma zamanında yapılan derlemenin tek değil, duruma göre çoklu versiyonlara sahip bir derleme olması. Bu sayede JIT derlemeyi birden fazla kez yapabilecek ve hızlı bir şekilde derlenmiş çıktı değişebilecek. Bu sayede de kodları daha hızlı çalışabilecek, hatta çalışıyor da. Bu olaya “Tiered Compilation” diyor .NET Core tarafı…

Biraz daha basite indirgeyip daha iyi anlayalım. Derlenmiş C# kodumuzun çıktısı MSIL, run-time zamanında JIT tarafından çok hızlı bir şekilde derleniyor(Tiered Compilation). Bu derleme aşamasında, kod çıktısı hızlı ayağa kalksın, motor hızlıca ısınsın(:P) diye belli optimizasyonlardan ferakat ediliyor. Eğer kod çok çalışan bir nokta ise derleme yine gerçekleşiyor ve farklı optimizasyonlar ile yine hızlı çalışan bir kod çıktısı oluyor.

Hepimizin bildiği; Release ve Debug modda derleyince farklı optimizasyonların yapılmış olmasını düşünün. Release modda derlendiğinde yapılan optimizasyonların uygulamanın çalışma şekline göre tekrar farklı farklı yapıldığını düşünün. Bu son “düşünün, düşünün” diye verdiğim örnek umarım biraz daha net anlaşılmasına yardımcı olur. 🙂

Başta da söylediğim gibi bu özellik, .NET Core 2.1 ile hayatımıza girmişti. Ancak *.csproj ya da environment değişkenlerinden aktif hale getirebiliyorduk. .NET Core 2.2 ile artık aktif hale getirmemize gerek yok. Varsayılan çalışma şekli olarak zaten aktif olacak. Ama benzer şekilde bu sefer de istersek, pasif hale almak mümkün olacak.

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>netcoreapp2.1</TargetFramework>
      <TieredCompilation>true(artık false yapıp kapatabiliriz)</TieredCompilation>
    </PropertyGroup>
</Project>

Arka taraftaki bu iyileştirme dediğim gibi geliştirme yaklaşımıza direkt dokunacak bir konu değil. Ama üzerinde çalıştığımız teknolojilerin, çalışma yapılarını ne kadar bilirsek, çözüm sağlama ve problem çözme yaklaşımlarımız o derece iyi olur düşüncesindeyim. Umarım bir şekilde de olsa faydası dokunur. Bir sonraki yazıda görüşmek üzere…

Blog’u uzun süredir takip edenler ya da az biraz tanışma fırsatı bulduğum kişiler Managed Extensibility Framework(MEF) ile ilk çıktığı günden beri haşır neşir olduğumu bilir. 🙂 Artık direkt .NET Framework’ün bir parçası olması belki farkındalığını biraz azalttı ama açıkcası .NET ile uygulama geliştirirken belli ihtiyaçları kolayca geliştirmek için güzel bir yapı.

MEF ne işe yarıyor, neler yapılabilir bunlara tekrar girmeyeceğim ama özet olması için;

  • Plug-in kavramı gibi ek parçalar ile uygulamalara yeni fonksiyonlar eklemek için ortaya çıkan bir yapı.
  • WPF, WinForms, ASP.NET gibi farklı uygulama tiplerinde kullanılabilmekte.
  • .NET Framework 4.0 ile beraber, .NET Framework’ün içine dahil edildi.
  • Uygulamanın bütünlüğünü çok değiştirmeden sadece fonkisyonları kolayca ekleyip, çıkarmak mümkün olabiliyor.

Daha önceleri paylaştığım yazılara da göz atmanızı tavsiye ederim. [MEF Yazıları]

Gelelim bu yazımızın konusuna; .NET Core’da Managed Extensibility Framework(MEF) kullanımı…

MEF, .NET Core’a Microsoft.Composition ile port edildi. Ama ne yazık ki tüm API’ları ile beraber edilmedi. Önemli bir kaç API port edilemese de, MEF’in karakteristik özelliklerini ve temel fonksiyonlarını sorunsuz bir şekilde .NET Core’da kullanabiliyoruz.

Port edilen API’lar sadece System.Composition namespace’indeki API’lar. Dolayısıyla MEF’deki en sevdiğim özelliklerden, kataloglar; AggregateCatalog, ApplicationCatalog, AssemblyCatalog .NET Core tarafında kullanılır durumda değil. Dolayısıyla MEF kullandığınız bir uygulamanızı .NET Core’a port etme çalışması içerisindeyseniz, MEF kısımlarında bir kaç düzenleme yapmanız gerekebilir.

Ayrıca sağlıklı MEF’i sağlıklı kullanmak için Microsoft.Composition 1.0.31 min. versiyon olacak şekilde kullanmanızı tavsiye ederim. Bir kaç sinir bozucu hata giderilmiş durumda. NuGet‘den versiyonları takip edebilirsiniz…

Neyse kafanızı yeteri kadar karıştırdığıma göre örnek kodlara geçelim…

Öncelikle MEF bileşeni olarak “export” etmek istediğimiz sınıflar için .NET Framework’de temel olarak ne yapıyorsak, .NET Core’da da devam.

Önce bir interface oluşturup, bu interface ile sınıfımızı geliştirip, [Export] özelliği ile MEF için dışarıya aktarılacak bir sınıf olduğunu belirtmemiz gerekmekte.


namespace NotifyMe.Common
{
    public interface IBaseTemplate
    {
        string Create(string message, string from, string image);
    }
}

//Export edeceğimiz sınıfların ayrı bir assembly'de olması,
//MEF'in genişletilebilir özellikleri sunması açısından doğru olacaktır.
namespace NotifyMe.Templates
{
    [Export("ChatMessage",typeof(IBaseTemplate))]
    public class ChatMessageBaseTemplate : IBaseTemplate
    {
        public string Create(string message, string from, string image)
        {
            //Burada takla atalım, zıplayalım, uçalım...
        }
    }
}

MEF’in tak-çıkart yaklaşımı ile fonksiyonları kullanma yaklaşımdan dolayı, tüm [Export]’ların ayrı assembly’ler yani ayrı projeler olmasına dikkat edin.

Şimdi de export ettiğimiz bileşenleri ana uygulamamızda nasıl alırız buna bakalım. .NET Core tarafında tüm katalogları kullanamadığımız için ContainerConfiguration sınıfı ile MEF bileşenleri için bir katalog oluşturup, bunun üzerinden bileşenleri alıyoruz.

Aşağıdaki örnek bir web uygulamasından(ASP.NET Core); örnekteki uygulamada root dizininde Plugins diye bir klasör var. Bu klasöre konan *.dll’ler, ana web uygulaması tarafından kontrol edilip yüklenmekte. Daha sonra _templates şeklinde bir liste üzerinden erişilebilir duruma geçiyor.Bu sayede bir ASP.NET Core uygulamasında herhangi bir değişiklik yapmadan sadece belli bir dizine(Plugins) ABC.dll’ini koyup belli fonksiyonları çalıştırmak mümkün. Eğer bu fonksiyonu değiştirmek gerekiyorsa, ana uygulamada bir değişiklik yapmadan ABC.dll’i yerine XYZ.dll’ini koyarak fonksiyonu değiştirmek oldukça kolay.


        [ImportMany]
        private IEnumerable<IBaseTemplate> _templates { get; set; }
        public MessageService(IHostingEnvironment hosting, ILogger<MessageService> logger)
        {
            _logger = logger;

            try
            {

                
                var rootPath = hosting.ContentRootPath;
                var path = Path.Combine(rootPath, "Plugins");
                var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories)
                            .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
                            .ToList();
                var pluginContainer = new ContainerConfiguration().WithAssemblies(assemblies);
                using (var container = pluginContainer.CreateContainer())
                {
                    _templates = container.GetExports<IBaseTemplate>("ChatMessage");
                }
            }
            catch (System.IO.DirectoryNotFoundException dnfe)
            {
                _logger.LogError(dnfe.Message);
            }
            catch (System.Exception ex)
            {
                _logger.LogError($"Unable to find message templates. {ex.Message}");
            }
        }

Hızlıca ve kısa oldu ama .NET Core tarafında da MEF API’larının kullanılabilir olduğunun farkındalığı bir çok ihtiyacınızı çok rahat bir şekilde karşılamanız için yol gösterecektir. Özellikle .NET Core’un “dependency injection” desteği ile MEF’in gücü birleştiği zaman ortaya güzel şeyler çıkıyor.

Office 365 kullanımı arttıkça yeni ihtiyaçlar ve özellikler ortaya çıkıyor. Microsoft Graph da bu ihtiyaçların sağlanması için ortaya çıkmış bir API platformu olarak yaklaşık 2-3 sene önce karşımıza çıktı. İlk çıktığında fiziksel olarak Office 365 sınırları içinde lanse edilse de, geçen sene Microsoft 365 konsepti ile; Office 365, Windows 10 ve mobil-güvenlik servislerini bir arada geliştirebilmek için gelecek vaat etti. Geçen sene Build 2017’de belli oturumlarda gösterilen demolar ile güzel heyecanlar yaşatmıştı…

Graph API

Office 365 kullanıyorsanız, platformun bir çok özelliğine Microsoft Graph API’ları ile erişmek mümkün. Bu sayede geliştirdiğiniz çözümler ile Office 365 çözümlerini entegre etmek ya da Office 365 ürünlerine eklentiler geliştirmek mümkün. Office 365’deki e-mail, OneDrive, OneNote, kullanıcı grupları, Planner, takvim vs. ürünlerindeki çeşitli özellikleri Graph API’ları ile kullanmak bir çok kapı açıyor. Office 365 API’ları ile bunları yapmak mümkün olabiliyordu kısmen, ama artık tek bir platformda Microsoft Graph çatısı altında ihtiyaçları sağlamak daha doğru ve geçerli. Ben demiyorum, Microsoft diyor… 🙂

Microsoft Graph API’ları özetle;

  • Azure AD
  • Outlook(E-Mail, Takvim, Kişiler, vs.)
  • OneDrive
  • SharePoint
  • OneNote
  • Planner
  • Yammer
  • Excel
  • Microsoft Teams
  • Intune
  • Azure AD Identity Protection
  • Azure Security Center

ürünlerinin çeşitli özelliklerine API olarak erişmek için güzel bir platform olarak karşımıza. Bu platformdaki API’lar REST ile sunulan bir yapıya sahip. Dolayısıyla bir çok farklı geliştirme teknolojisi; .NET Framework, PHP, Python, Swift(iOS), Objective-C(iOS), Android, Ruby, Node.js gibi, bu API’ları kullanmak mümkün.

Graph API

Yukarda da dediğim gibi geliştirdiğimiz çözümlere bu ürünlerdeki özellikleri katmak ya da bu ürünlere eklentiler geliştirmek bir çok kapıyı açıyor.

Daha önce GitHubda bir PoC çalışması için bir şeyler karalamıştım. Bunun üzerinden kurcalayıp siz de farklı API’lar ile farklı ihtiyaçlarınızı karşılayabilirsiniz. Orda basit olarak bir Office 365’deki Outlook e-mail hesabına gelen e-mail’leri filtreleyip belli bir operasyon gerçekleştirmenin senaryosu vardı. Kurumsal bir çok firmada, belli süreçleri otomatikleştirmek için tercih edilen bir senaryo, tanıdık gelmiştir. 🙂 🙂

Microsoft Graph API’ları ile bunu gerçekleştirmek, gelen bir e-mail’i parse edip, içeriğine göre Planner’da bir görev yaratmak, daha sonra e-mail’in eklerini OneDrive’a kaydedip kendi geliştirdiğiniz ERP uygulamasında süreç başlatmak gibi senaryolar oldukça kolay. Diğer API’lar ile daha kompleks ihtiyaçları kolay bir şekilde gerçekleştirebiliyoruz.

Microsoft Graph farkındalığı ve API’lara giriş için umarım biraz olsun kıvılcım yakar. Şimdilik bu kadar. Merak ettiğiniz, takıldığınız noktalar olursa; biliyorsunuz… 😉

Bu arada daha derinlere girmek için aşağıdaki kaynakları şiddetle öneririm.

Şu dönem .NET Core 2.2-Preview-1 ile gelişmeye devam eden ASP.NET Core, direkt framework içinde yerleşik olarak gelen “Dependency Injection(DI)” yaklaşımı bir çok açıdan kolaylıklar sağlıyor. Belli yapıları, geliştirilen uygulamalara enjekte etmek, uygulama fonksiyonlarının bağımlılıklarını sağlıklı yönetmek ve “seperation of concerns” prensibine sadık kalabilmek için DI oldukça gerekli. ASP.NET Core ile bunun yerleşik olarak sunulması, bağımlılıkların karmaşaya dönüşmesine uygun olan web uygulamaları için oldukça faydalı ve kolay bir özellik.

Bu kısa girişten sonra asıl konumuza gelelim; View ya da PageModel’larda(Razor Pages) bir bağlılığı nasıl kullanırız? Yani bir başka değişle *.cshtml’lerde bağımlılıkları nasıl kullanırız…

Enjekte ediyoruz…

ASP.NET Core’da Razor sayfalarda ya da View’larda @inject yöntemi ile bağımlılıkları sayfaların ön yüz tarafında kolay bir şekilde enjekte edebiliyoruz. Bu şekilde bir sayfada gösterilecek “data”’yı ASP.NET Core uygulamasına bağladğımız bir servis ile gösterebiliyoruz. Ne amaçla kullanabileceğimizden bahsetmek daha anlaşılır olmasını sağlayacak sanırım. Razor sayfası ya da View’de bir HTML “unordered list(<ul>)” elemanının içeriğini doldurma ihtiyacımız olsun ya da bir <select> elemanını… Bunun için View’e enjekte ettiğimiz bir servisi kullanarak kolaylıkla doldurabiliriz. Bunu tabi ki “Model” ya da “ViewData” ile yapmak da mümkün.Ama şöyle bir senaryonuz olduğunu düşünün; “multi-culture” bir uygulamanız var ve dil özelliklerine göre Model ya da ViewData’dan gelen veriler dil seçeneğine göre göstermeniz gerekiyor. 1 şeklinde gelen veriyi; “Yes, Ja, Si, Evet” şeklinde göstermek gibi. Bunun için dil değerlerini ViewData’ya gömmek yerine enjekte edilen farklı bir servis ile UI tarafında göstermek daha doğru olacaktır. Bu şekilde “seperation of concerns” prensibi de sağlanmış olur.

Peki bunu nasıl yapıyoruz…

Öncelikle bir servis oluşturmamız gerekiyor. Servisi burada, public olarak metotları olan bir sınıfı olarak düşünün. Public bir sınıfın, public metotları ile veri sağlayan bir yapı…

    public class VisitorService
    {
        private IServiceProvider _provider;
        private NotifyDbContext _db;
        public VisitorService(IServiceProvider provider, IConfiguration configuration)
        {
            _provider = provider;
            _db = (NotifyDbContext)_provider.GetService(typeof(NotifyDbContext));
        }
        public int GetActiveVisitorCount() => _db.Connections.Where(c => c.Connected).Count();
    }

Bu servisi, ASP.NET Core uygulamasının servislerini tanımladığımız yerde uygulamaya eklememiz gerekiyor.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<VisitorService>();
            ....
            ..
            .
        }

ASP.NET Core’un içinde yerleşik olarak gelen DI yaklaşımının kilit noktası burası. Burada önemli olan 3 farklı ekleme yöntemi var.

  • .AddTransient<TService>(): Her request için yeni bir instance yaratırılır ve kullanılır.
  • .AddSingleton<TService>(): İlk request ile yaratılan, tek bir instance kullanılır.
  • .AddScoped<TService>(): Belli bir kapsam(web request) içinde her request de yaratılan instance kullanılır.

Servis tanımlarını bu şekilde yaparak, TService tipinde oluşturulan servis nesnesinin yaşam süresini belirtiyoruz. Bunların ayrıntılarına çok girmeyeceğim şimdi. Bu şekilde yaşam süresini belirttiğimiz servis nasıl View’larımızda kullanırız buna hızlıca bakalım.

*.cshtml sayfamızda @inject anahtarını kullanarak önce servisi sayfamız için tanımlıyoruz.

Burada @inject {Servisin sınıf adı} {Instance adı} şeklinde bir kalıp kullanmak gerekiyor.

Daha sonra *.cshtml sayfasının içinde istenilen yerde @{Instance adı}.ServisMetodu şeklinde ilgili servisin metoduna ulaşmak mümkün.

@using Microsoft.AspNetCore.Identity

@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject NotifyMe.Services.VisitorService VisitorService
@if (SignInManager.IsSignedIn(User))
{
    <a title="Active users count" asp-page="/Users">@VisitorService.GetActiveVisitorCount()</a>
    .....
    ..
    .
}

Bu kısa yazı ile hızlıca ASP.NET Core’da @inject ile bağımlılıkların *.cshtml tarafında nasıl yapılabileceğini görmüş olduk. Oldukça kolay ve hızlı bir şekilde belli ihtiyaçları hızlıca karşılamak bu sayede mümkün. Bunun farkındalığında olmak ve gerektiği yerde, olması gerektiği gibi kullanmak uygulamanızın kalitesini arttıracaktır; kesin bilgi, yayalım… 🙂 🙂

Güncelleme: Bu yazıyı yayınladıktan sonra Visual Studio Team Services(VSTS), Azure DevOps olarak bir isim değişikliğine uğradı. Yazıdaki bahsetmeye çalıştığım her konu hala geçerli.

Açık kaynak projelerin kod deposu olarak hayatımıza giren GitHub, yazılım teknolojilerinin olmazsa olmaz bir parçası oldu artık. Benzer şekilde Visual Studio Team Services(VSTS)’de uçtan uça bir kod geliştirme alt yapısı sunduğu ve bulut servisi olmasından dolayı da oldukça tercih edilen bir platform. Özellikle Team Foundation Server(TFS) ile bir şekilde haşır neşir olanların bir sonraki basamağı…Neyse şimdi VSTS’in ayrıntılarına girmeyelim, çıkamayız.

Bu yazıda basit bir senaryo ile GitHub’da kodlarını barındırdığımız bir projeyi, VSTS üzerindeki bir “build-relase” adımları ile Azure’da ki bir App Service’e dağıtımını yapacağız. Bir nevi Continuous Deployment(CD) sürecini basitçe bir VSTS üzerinde oluşturacağımız bir pipeline ile gerçekleştireceğiz. Anahtar kelimeleri de paylaştığıma göre başlayabilirim 🙂

Bu arada bu bahsetmiş olduğum senaryoyu bu yazıyı yazdığımdan daha kısa sürede gerçekleştirdim. Artık kullanılan sistem ve platformların etkin ve kolay olması bir çok ihtiyacta kurtarıcı oluyor. DevOps yaklaşımı anlamak, farklı sistemler ile bir uygulamayı nasıl belli platformlara dağıtabiliriz ön ayak olması için umarım faydalı olur.

Build…

Bu senaryoda GitHub’daki Notify.Me projemdeki kod repository’sini kullanacağım.(Belli bir PoC çalışması için yapılan, ASP.NET Core ile SignalR projesi) Zaten bir kod kaynağımız olduğu için ilk iş olarak VSTS’de Build adımını gerçekleştirmek. VSTS’deki menüdeki “Build and release” başlığından “Builds” menüsüne giriyoruz.

Haaaa; bu arada, bu yazıdaki ekran görüntüleri sizin VSTS hesabınızdan farklı ise, sağ üst köşedeki kullanıcınız üzerinden “Preview features”dan yeni görsel özellikleri açabilirsiniz.

“Builds” kısmında kod deposu olarak seçebileceğimiz seçenekleri göreceksiniz. Burada oldukça geniş bir kümeye sahibiz; Team Foundation Version Control(TFVC), GitHub, Bitbucket, Subversion. Yok yok… 🙂

Biz GitHub’ı seçiyoruz tabi ki. GitHub’ı seçince, GitHub hesabımız ile VSTS’i ilişkilendirmek için Login olmamız ve sonrasında gerekli izinleri vermemiz gerekiyor. Ekranların yönlendirmesi ile kolayca bunları yaptıktan sonra, GitHub’daki hangi projemizi derlemek istiyorsak onu seçiyoruz. Projemizde farklı branch’ler varsa, derleme işlemi için onu da belirtiyoruz.

Daha sonra gerek duyduğumuz derleme şablonunu seçiyoruz. Bu şablonlar derleme aşaması için genel kullanımlarda gerek duyulan adımların oluşturulduğu hazır şablonlar. Bu şablonlardan birini seçmek yerine direkt olarak boş bir şablon oluşturup, adımları kendiniz ekleyebilirsiniz.

Notify.Me bir ASP.NET Core 2.x uygulaması olduğu için, burda ASP.NET Core şablonunu seçiyorum. Daha sonra seçtiğim derleme şablonuna göre belli adımlar karşımıza çıkıyor. Bu ekranda, bu adımların ayarlarını düzenlemek yetiyor. Hangi komutların çalışacağı, hangi projelerin build olacağını gibi ayarlar…

Açıkcası burada ekranlar oldukça kolay ve güzel oluşturulmuş diye düşünüyorum. Takıldığınız bir adım olursa onun çeşitli label’ları ile adım hakkında bilgi ve hatta ayrıntılı ek bilginin linki oluyor.

Bu senaryoda seçtiğim GitHub repository’sinde hangi projeyi build edeceğimi ayarlıyorum, ayrıca Restore ve Test görevlerini de disable ediyorum. İstediğimiz adımları enable/disable edip “Build Pipeline”nında çeşitli durumları deneyebiliriz. Komple de kaldırabiliriz tabi ki. Hatta isterseniz farklı görevler(task) ekleyerek build aksiyonlarını zenginleştirebilirsiniz. VSTS’in mevcut taskları dışında, Visual Studio Marketplace’den de farklı task’ları kullanabilirsiniz. Tek tek bunlardan bahsetmeyeceğim, -ki edemem zaten,zamanımız yetmez 🙂 Ama oldukça zengin bir görev kümesi mevcut.

“Build” işleminin nasıl tetikleneceğini de derleme ayarlarındaki “Triggers” altından ayarlamak mümkün. GitHub’daki projeye her bir commit‘de build adımını tetikleyebiliyorum bu şekilde. Sadece belli branch’lere yapılan commit’leri ya da GitHub’daki “Pull Request”lere göre de tetiklemek mümkün.

Read More

İnsanoğlunun zaman ilerledikçe bazı aksiyonları almakta ve değişikliklere adapte olmakta zorlanması gibi, “yaşlanmak” dediğimiz gerçekler, yazılım uygulamaları ve çözümleri içinde geçerli. Yazılım çözümlerinin çok yaygın olduğu bir çağda yaşadığımız ve etrafımızın yazılımlar ile çevrili olmasından dolayı bu “yaşlanan” yazılım çözümleri ile daha sık karşılaşıyoruz.

Yaşlanan yazılım uygulamaları için genellikle yazılım dünyası insanları olarak “Legacy” tabirini kullanırız bildiğiniz gibi. Biraz daha net anlamı anlamak için; “Günün şartlarına uymayan uygulamalar ve çözümlere “Legacy” uygulamalar diyoruz” diyebilirim. 10 yıl önce, hatta daha da önce geliştirilen ve hala kullanılan, ama artık negatif yönlerinin ağır bastığı, belli ihtiyaçları karşılamasının zor olduğu “Legacy” uygulamalar eminim bir çok kişinin karşısına çıkıyordur.

“Legacy” uygulamalar günün şartlarına uymamaları, adaptasyon güçlükleri yaşatmalarından dolayı oldukça zorlayıcı uygulamalar olabilir. Günün şartlarına uymamaları derken, atıl kalan donanımlar, desteklenmeyen işletim sistemleri, veri saklama sistemleri, değişim ihtiyaçları, performans durumları, kullanım şekillerinin çeşitliliği vs. bir çok başlık sayabilirim ama şimdi bunlara girmiyoruz.

Windows NT’den nerelere geldik 🙂

Windows NT üzerinde çalışan, PHP 3.0 ile geliştirilmiş, WEB bileşenleri sadece Internet Explorer’da düzgün çalışan, RDBMS olarak SQL Server 7.0 kullanan bir uygulamanın günümüzde hala yoğun bir şekilde kullanıldığını düşünün…Günümüze gelene kadar alt yapı olarak geliştirmelerin ve upgrade’lerin riskleri, iş ihtiyaçlarının en önemli olduğu algısı ve en önemlisi de insan faktörü yüzünden uygulama bu zamanın şartlarına uymayan bir çözüm olarak karşımızda…

Çok uç bileşenler ile bir örnekleri oldu ama benzer senaryolar var.

Bu tarz uygulamalar ne kadar zorlayıcı da olsa, günün IT çalışanları tarafından “offf poff” şeklinde yaklaşılıp, ne kadar çok negatif şey söylense de (bu arada hepsi genelde doğrudur), unutulmaması gereken çok önemli bir nokta var; “Değer”.

“Legacy” dediğimiz uygulamalar, sistemler öyle önemli bir değer yaratmışlar ki hala günümüze denk yaşayabilmişlerdir demek ki. 10, 15, 20 yıldır ayakta olan uygulamaları düşünün; ilk kullanıldıkları dönemlerden beri insanlara ve belli iş modellerine o kadar çok değer katıyorlar ki, hala o değeri koruma mücadelesinde içindeler… Biraz daha toparlamak gerekirse “Legacy” diye adlandırdığımız uygulamalar, ne kadar çok negatif bileşenle günümüze gelse de sahip oldukları “değer” çok önemlidir… Ve bu değer uygulamaların en güçlü özelliğidir.

Bir uygulamanın “Legacy” olarak adlandırılmaması, 10 yıl sonra da günün ihtiyaçlarını kolaylıkla karşılayabilmesi, bir 10 yıl sonra kattığı değerin üstüne yeni değerleri koyabilmesi için neler yapılması lazım, nasıl geliştirilmesi lazım falan filan bunlardan şimdi bahsetmeyeceğim… Derya deniz konular çünkü…15-20 yıl önce bir uygulamayı değişime hazır bir şekilde geliştirmek, bulunduğu zamanın ihtiyaçlarına uygun geliştirmek pek mümkün değildi belki, ama günümüzdeki yaklaşımlar yazılımların ömürlerini biraz daha kaliteli kılmayı sağlıyor. Arada karalarım ama bir şeyler.

Read More