Java Rules: “catch” clauses should do more than rethrow

catch clause that only rethrows the caught exception has the same effect as omitting the catch altogether and letting it bubble up automatically, but with more code and the additional detrement of leaving maintainers scratching their heads.

Such clauses should either be eliminated or populated with the appropriate logic.

Noncompliant Code Example

public String readFile(File f) {
  StringBuilder sb = new StringBuilder();
  try {
    FileReader fileReader = new FileReader(fileName);
    BufferedReader bufferedReader = new BufferedReader(fileReader);

    while((line = bufferedReader.readLine()) != null) {
      //...
  }
  catch (IOException e) {  // Noncompliant
    throw e;
  }
  return sb.toString();
}

Compliant Solution

public String readFile(File f) {
  StringBuilder sb = new StringBuilder();
  try {
    FileReader fileReader = new FileReader(fileName);
    BufferedReader bufferedReader = new BufferedReader(fileReader);

    while((line = bufferedReader.readLine()) != null) {
      //...
  }
  catch (IOException e) {
    logger.LogError(e);
    throw e;
  }
  return sb.toString();
}

or

public String readFile(File f) throws IOException {
  StringBuilder sb = new StringBuilder();
  FileReader fileReader = new FileReader(fileName);
  BufferedReader bufferedReader = new BufferedReader(fileReader);

  while((line = bufferedReader.readLine()) != null) {
    //...

  return sb.toString();
}

See

Advertisements

Design Patterns

Tasarım Şablonları
Tasarım Şablonları

Creational Design Patterns

  1. Abstract factory
  2. Builder
  3. Factory kit
    • fonksiyonel
  4. Factory method
  5. Module
  6. Monostate
  7. Multiton
  8. Singleton
  9. Prototype

Structural Design Patterns

  1. Abstract document
  2. Adapter
  3. Bridge
  4. Composite
  5. Decorator
  6. Event aggregator
  7. Facade
  8. Flyweight
    • performans

Behavioral Design Patterns

  • Mediator
  • Memento
  • Intercepting filter
  • Interpreter
  • Iterator
  • Chain of responsibility
  • Command
    • fonksiyonel
  • Delegation
  • Dependency injection
  • Extension objects
  • Feature toggle

Architectural Design Patterns

  1. Api gateway
    • spring
  2. Aggregator microservices
  3. CQRS
  4. Event driven architecture
  5. Hexagonal architecture
  6. Naked objects
  7. Data bus
  8. Data transfer object (dto)
  9. Layers

Other Design Patterns

Concurrency Oriented Design Patterns

  1. Async method invocation
    • fonksiyonel
    • reaktif
  2. Balking
  3. Double checked locking
  4. Event queue
  5. Event-Based asynchronous
  6. Guarded suspension
  7. Half-Sync / Half-Async
  8. Mutex

Other

  1. Double dispatch
  2. Execute around
  3. Mute idom
  4. Flux
    • sunum katmanı
  5. Front controller
    • sunum katmanı
  6. Model view controller (mvc)
    • sunum katmanı
  7. Model view presenter (mvp)
    • sunum katmanı
  8. Data mapper
    • süreklilik katmanı
  9. Data access object (dao)
    • süreklilik katmanı
  10. Business Delegate
    • iş katmanı
  11. Message channel
    • entegrasyon
    • apache camel
  12. Caching
    • performans
  13. Lazy loading
    • performans
  14. Callback
    • fonksiyonel
  15. Fluent interface
    • fonksiyonel
  16. Monad
    • fonksiyonel
Core J2ee Patterns
Core Java Tasarım Şablonları

Java Design Patterns Cheatsheet

SpringBoot ile Rest ve Soap Api Örneği

SpringBoot Nedir?

SpringBoot, hızlıca deploy edilebilir yeni nesil web uygulaması oluşturmaya yarayan güzel bir spring implementasyonudur. Çalıştırılabilir jar dosyası çıkartarak web uygulaması ya da servis yazılabilir. Ben bu alt yapıyı kullanarak bir servis yazmak istedim.

Uygulamanın Amacı Nedir?

Servisimde “Poi” adında bir entity’yi crud işlemlerine tabi tutarak, “spring ile nasıl soap api yazılır“, “spring ile nasıl rest api yazılır” sorularına çözüm göstereceğim. Asıl amacım poi’nin hangi property’sini işlediğim değil, spring ile onu nasıl kullandığım olacak.

Servisimi yazarken, Spring’i de yeni öğreniyor oluşumdan dolayı spring’in annotation’larını doğru kullanmaya ve neden kullandığımı da açıklamaya özen göstereceğim. Ayrıca core, webService ve business lojiklerini doğru kullanmayı hedeflediğim güzel bir alıştırma projesi olacak.

Neler Anlatacağım?

Kodları yazı içinde paylaşmak yerine github’ı kullanacağım. Burada anlatacağım şeyler ise, yazılma amacı ve nasıl çalıştığı olacak.

https://github.com/sefersezer/SpringRestSoapApiExample


Proje kaynaklarını anlatmaya öncelikle maven dependencylerinden başlayacağım.

lombok: Compile time’da pojo’lardaki getter, setter, default constructor vb şeyleri otomatik oluşturan, kod kirliliğini azaltmayı sağlayan bir eklenti. Lombok, başka bir makalede detaylıca anlatılabilir.

spring-boot-starter-web: Uygulama web projesi olarak ayağa kalkıp bir portu kullanılabilir sunacak. Ayrıca ws paketinde spring boot web annotationlarını da kullanacağız.

spring-boot-starter-data-mongodb: Veritabanı olarak mongodb kullanacağım. Mongodb bağlantısını da spring yetenekleriyle kuracağım.

spring-boot-starter-ws: Spring web service annotationları için kullanıyorum. Mesela @Endpoint annotation’u soap (ve rest) actionlarını işlemek için projeyi otomatik tarayarak geçtiği sayfadaki @ResponsePayload’lı methodları kullanılabilir kılacak.

wsdl4j: soap api için xsd şablonundan wsdl generate etmeye yarayacak. Örneğin servis endpointi sonuna .wsdl koyarak şablona erişebiliyor olacağım.  (localhost:9000/ services /poiservice.wsdl )

modelmapper-spring: Core package ile Web Service package’larının bağımsız olacağından bahsetmiştik. Hedef pojo’m olan Poi için Web Service katmanında PoiEntity objesi oluşturdum. Bunların her bir property’sini manuel maplemek yerine modelMapper kullanacağım.

jackson: Serializabled objelerimi json, xml setlere dönüştürüp, büyük angaryadan kurtaran muhteşem dependency. #tambiraltinbilezik 🙂

jaxb2-maven-plugin: xsd şablonunu oluşturduktan sonra servis katmanındaki objeler için elle uğraşmayacağım heralde! mvn clean generate-sources ile deploy ettiğimiz zaman belirtilen dizine otomatik generate edilecek. (Artık javada pojo oluşturmak angarya iş olarak gözüküyor. Örneğin eclipse’de Telosys Tools ile pojo, dta, dto, testler vs birçok şey generate edebiliyorsunuz.)


Uygulamanın modüllerini (paketleri) ve sınıf isimlerini aşağıdaki gibi verdim:

  • config
    Spring'in Mongodb bağlantısını sağlamak için özel bir dependency eklemiştik.
    Bu dependency @EnableMongoRepositories annotation'ı sağlıyor. Mongodb
    repositorylerinin bulunduğu paketi göstererek (bir nevi) register ediyoruz.
    Ayrıca bağlantı kurarken host, port, db parametrelerini de
    AbstractMongoConfiguration sınıfını extend ederek set edebiliyoruz.
    
    Burada kullandığım Environment değerleri ise /resources/application.properties
    dosyasından geliyor.
    • MongoConfig.java
  • model
    Uygulamada Poi.java ve PoiEntity.java adında aynı gözüken ama 2 farklı amaca
    hizmet eden pojo bulunuyor. Ben her ne kadar bu projede extreme işlem yapmasam
    da modüllerin bağımsızlığının sağlanması gerektiğini gösterebilmek adına bu
    iki pojo'yu oluşturdum.
    
    Poi.java, uygulamanın core tarafındaki model entity'm olacak. Core tarafındaki
    işlemlerde bunu istediğim gibi manipule edeceğim; complex type olarak kullanıp içine istatiksel veriler vs ekleyip, gerekirse başka yerden
    implemente edilmiş özellikler vs kullanıp istediğim gibi kullanabileceğim.
    Servis tarafındaki PoiEntity.java ise, Poi.java'daki implementasyonlarımın
    çıktısı olacak. Kullanıcıya göstermek istediğim şeyleri en yalın haliyle
    oraya atacağım. Kullanıcı benim arka planda ne yaptığımdan, core'daki
    bağımlılıklarımdan haberdar olmayacak, sadece bu çıktıyı alıp kendi işine
    bakacak.
    
    Mapper, poi ile poiEntity'deki gerekli property'leri birbirine map ettiğim
    mapping servisim. Sınıfı incelediğimizde, normalde daha çok karışık olması
    gerekir ama bu uygulamada bişey yapmadığımdan ModelMapper dependency'sini
    kullanarak direkt mapping sağladım.
    
    repository/ dizinindeki poiRepository ise, mongodb'deki collection'a ulaşmamı
    sağlayan mongoDbRepository örneğim. FindAll, save, delete default işlemlerini
    mongoDbRepository sayesinde yapabiliyorum. Spesifik sorgularım için ise
    namedQuery denilen spring özelliği ile yazdığım methodlara uygun ismi ve dönüş
    tipi vererek crud işlemimi gerçekleştirebiliyorum. Detaylar için şu adrese
    bakabilirsiniz.
    • repository
      • PoiRepository.java
    • Mapper.java
    • Poi.java
  • service
     (acıklama)
    • endpoint
      • PoiRestEndpoint.java
      • PoiSoapEndpoint.java
    • PoiRepositoryService.java
  • ws
     (acıklama)
    • model
       (acıklama)
      • PoiEntity.java
      • ServiceResponse.java
    • rest
       (acıklama)
      • EntityService
      • EntityServiceImpl
    • soap
       (acıklama)
      • dao
        • DeletePoiRequest.java
        • GetPoiRequest.java
        • GetPoiResponse.java
        • ObjectFactory.java
        • package-info.java
        • SavePoiRequest.java
      • SoapWebServiceConfig.java
  • Application.java
    Uygulama bu sınıf ile ayağa kalkıyor. Sınıfa SpringBootApplication annotation
    ve diğer annotationları vererek, springBoot uygulaması olmasını, servis olarak
    çalışmasını, konfigurasyonları okumasını vs söylüyorum; ilk kıvılcımı buradan veriyoruz.
  • resources
     (acıklama)
    • application.properties
    • poiservice.xsd

 

Blog Başlıkları

Merhabalar,

Aklımda yüze yakın sayıda blog konusu var. Bunları yazmak isterim ama tipik Y kuşağı insanı olduğumdan hiçbirşey yapmamak daha cazip geliyor.

Tabi, o kadar da değil; yazıcam bu blogları. Buraya aklımdaki blog başlıklarını not etmek, ilerde de yazdıkça burada üzerini çizmek istiyorum.

Listeye şöyle başlıyorum:

  • Arduino İle Digital Port Dinlemek
  • Maven Parent <> Dependency Versiyon İlişkisi
  • Maven Deneyimlerim
  • Jenkins Hakkındaki Yorumlarım
  • Docker Hakkındaki Yorumlarım
  • Coordinate Clustering (DBSCAN Algorithm)

Apache Web Server, Load Balance & Clustering ve Site Routing – Bölüm 2

Konu 2: Load balancing yönetimi sağlayan bir yapı tasarlamayı düşünüyorsunuz.

Bir uygulamanız var. (seferOver v2.0) Bu Tomcat veya JBoss Application Server altında çalışıyor. Bir gün stabil çalışmayacak hale gelene kadar (memory leak – genellikle geliştirici hatasından kaynaklanan overflow error | https://plumbr.eu/  bir göz atın.) çok istek geldiğini gördünüz, uygulama çok trafik yükü altında kaldı ve dikey yükselmenin (bandwidth genişletme, yeni trafik alanı satın alma, memory upgrade, cpu upgrade) yetersiz olduğunu, yatay yükselmeye ihtiyacınız olduğunu farkettiniz.

Uygulamanının içinde session yönetimi yapılmalı ve bearer token kullanmıyor / kullanamıyorsunuz (http://en.wikipedia.org/wiki/OAuth) (Bu durumda MemCache veya EhCache kullanılmalı)

Yatay genişleme için birden fazla (vm veya dedicated fark etmez – Artık bizim için dedicated sunucu ayırımı yok. Hepsi aynı.) sunucuya sahipsiniz. Uygulama sunucunuzu ve uygulamanızı her birine kurup eşit veya isteğiniz oranlarda istek yükü paylaşımı yapmak (process yükü değil, request – response yükü) istiyorsunuz.

Uygulamanız sadece servis ve arayüz olarak değil dosya – lisans üretme yeteneğine sahip ve her istediğinizde her makineden doğru yanıt gelmesini istiyorsunuz… (bunun anlatacağım konuyla direkt olarak ilgisi yok. Bu konu için memcache veya ehcache kullanılmalı.)

Gereken Malzemeler:

  • Birden fazla server (test için aynı server üzerinde de yapabilirsiniz)
    Internal Lan Ip’leri 10.11.12.{13 , 14 ve 15} olan makineleri kullandım.
  • Apache Web Server (10.11.12.13)
  • Apache Web Server için mod_jk.so
  • Birden fazla Tomcat (tomcat1: 10.11.12.14 ve tomcat2: 10.11.12.15)
  • Bir uygulama. (uygulamanız kendi içinde tomcat veya jboss taşıyabilir halde de olabilir. Bu durum için farklı bir konfigurasyona gerek duyulmamaktadır.)

Uygulanan Ortam:

  • Centos 64 bit server (test amaçlı olduğu için önce 1 server üzerinde çalıştım. Sonradan farklı makinelerde test için workers.properties dosyasında localhost değerlerini internal lan IP’leri ile update etmem yeterli oldu)
  • text editör olarak nano,
  • iptables servisi,
  • Apache web server’ın yönetimi ele alması için SELinux ayarlarına erişim ve
  • Sistemi restart edebilmek için root kullanıcı yetkisi.

ve gelelim Yapılan İşlemlere:

  • Apache web server 80 portunda çalışacak. Bunda sorun yok.
    service httpd start | restart | stop ile yönetebiliyoruz. ok
  • Tomcat1‘ in conf/server.xml dosyasında aşağıdaki parametreyi http protokolü ile bu tomcat’e erişilmesini istemediğimden comment içine aldım.
<!-- <Connector port="8081" protocol="HTTP/1.1"
 connectionTimeout="20000"
 redirectPort="8443" />
 -->
  • Şimdi ajp protokolünü devreye sokalım. Tomcat1 için 8081 portu kullanılsın. Burda redirectPort parametresine karışmadım. Sadece port parametresini değiştirdim. Tomcatimiz apache’ye bu port üzerinden ajp protokolü ile haberleşecek. http üzerinden direkt tomcat’e erişme imkanımız, yukarıdaki blok comment’e alındığından mümkün değil. Eğer http de açık olsun isterseniz (test sürecinde) Http protokolü ile ajp protokolünü aynı porta vermemelisiniz.
 <Connector port="8081" protocol="AJP/1.3" redirectPort="8443" />
  • Aynı makinede 2 tomcat varsa ve birini kapatmanız gerektiği durumda diğerini etkilememesini – çakışmamasını istiyorsanız shutdown portunu da ayarlamanız gerekmektedir.
    Port değişimi:
 <Server port="8005" shutdown="SHUTDOWN">
  • Worker tanımlaması:Not: Eğer tomcat1 deki worker tanımlaması buna yapılırsa ağırlık ve istek önceliği bu sisteme verilecek. Hangisinin öncelikli yanıt vereceğini, hangisinin IDLE olarak bekleyeceğini jvmRoute parametresi belirliyor.
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="worker1">
  • İçerik Tanımlaması:

Evet. Burası sıkıntılı. Şimdi ben uygulamamın adını myapp olarak ayarladım diyelim. Normal şartlarda tomcat’te “/myapp” veya “/”(root) path de çalıştırabilme imkanım var. Bunu zaten biliyoruz. Routing konfigurasyona geldiğimizde ise, sadece /myapp altında çalıştırma imkanım kalıyor. Ben root ‘ta çalıştırma imkanı bulamadım. Benim asıl uygulamam routing konfigurasyonunda yaptığım ayarlamalar ile root’ta çalışmadı. Belki de ben becerememiş olabilirim.

mod_proxy ile ve url redirect komutları ile /myapp dizinindeki uygulamayı root’ta göstermeyi de, virtual path yaratmayı da denedim. Belki de uygulamamdaki bir problemden kaynaklı olarak bunu becerememiş olabilirim. Çünkü küçükcük ufacık tefecik programlarla bunları becerebildim; benim kurmaya çalıştığım uygulama spring ile harmanlı olduğu için baharatları gaz yapmış olabilir (:

<Context path="/myapp" docBase="myapp" debug="0" privileged="true" />
  • Tomcat2 için yukardaki işlemleri tekrarlıyoruz
    jvmRoute=”Worker1″ konfigurasyonunu tomcat2 için yapmıyoruz. Ajp portunu aynı makinede ise 8082 yapabilirsiniz. Aynı makine üzerinde olacaksa port farklı olmalıdır. Farklı makine üzerinden apache web server’a request/response gönderecekse farklı port olmasına gerek olmamaktadır. Hatta bu durumda her ikisi de 80 bile olabilir yani.
  • Apache Web Server yüklenmiş olması gerekliliğini atlamış olabilir miyim – evet.
yum install httpd
  • Apache Web Server yüklemesinden sonra /etc/httpd/conf/httpd.conf dosyasında commentli olarak aşağıdaki yazıya benzer birşey bulunmaktadır. Onu pageDown ile gezerek bulup commentsiz olarak şunu yapıştırıyoruz
ServerName localhost:80
  • /etc/httpd/modules/ dizinine mod_jk.so dosyası kopyalandı
  • /etc/httpd/conf/httpd.conf dosyası içinde, diğer LoadModule işlemlerinin sonuna şu ayarlar yapıldı:

Burada Jk mount ayarlamalarım var. Eğer uygulamanızı root path’de çalıştırabiliyorsanız aşağıdaki gibi olacak. Eğer root path da çalışmıyorsa mecbur sonu yıldızlı isminin olduğu path’den çağırılacak. ” JkMount /myapp* myapp ”

#SEFER BEGIN
LoadModule jk_module modules/mod_jk.so
JkWorkersFile /etc/httpd/conf/workers.properties
#JkLogFile /etc/httpd/conf/mod_jk.log
#JkLogLevel info
#JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /status status 
JkMount /* myapp
JkMountCopy On
#SEFER END
  • Apache için /etc/httpd/conf/ dizinine yeni bir workers.properties dosyası oluşturuldu:
worker.list=loadbalancer,status
 worker.worker1.port=8081
 worker.worker1.host=10.11.12.14
 worker.worker1.type=ajp13
 worker.worker2.port=8081
 worker.worker2.host=10.11.12.15
 worker.worker2.type=ajp13
 worker.worker1.lbfactor=1
 worker.worker2.lbfactor=1
 worker.loadbalancer.type=lb
 worker.loadbalancer.balance_workers=worker1,worker2
 worker.status.type=status

Burada Tomcatler için tanımlanan portlar worker olarak girildi

lbfactor ile yük oranı 3:1, 4:2 tarzında (1:1) tanımlandı.

  • Centos sunucusu için SELINUX ayarı kapatıldı.

/etc/sysconfig/selinux dosyası için şu yönergeler izlenebilir.

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled. ***bununla değiştirdim.**
SELINUX=permissive
# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted
# SETLOCALDEFS= Check local definition changes
SETLOCALDEFS=0

  • Sistem restart edildi
  • Httpd servisi başlatıldı, tomcatler çalıştırıldı.

İşlemler bu kadar. Yazının başında bahsettiğim ihtiyaçları karşılayabilecek yapıyı kurduk. Balance ayarlarını kullacağınız sistemlerin ağ ve donanım hızlarına göre ayarlayabilirsiniz. Tertemiz oldu. Hepsi bukadar.

Apache Web Server, Load Balance & Clustering ve Site Routing – Bölüm 1

Konu 1: Bir apache Serverda birden fazla farklı tomcat’ı çalıştırmak istiyorsunuz.

Bunlar farklı uygulamalar çalıştıran tomcat’ler ve biri durdurulursa diğeri etkilenmemeli.

Aynı domain veya IP altından internete çıkmalılar. Port numarası görmek istemiyorsunuz.
Örneğin developer.sefersezer.com/jira ve developer.sefersezer.com/wiki

Dışarıdan bu uygulamalara erişilmesini istemiyorsunuz. Direkt olarak tomcat1’in bulunduğu makineye istek gitmesin, apache web server bunu yönetsin istiyorsunuz.

Yönetimini sağlayan apache web server makinesi ile aynı veya farklı makineler altında olabilme esnekliğine ihtiyacınız var; yani web server’a birşey olma durumunda farklı web server altından bu tomcatleri dışarıya çıkarmayı istiyorsunuz.

Sen Neymişsin Be Java!

“Java biliyorum” diyebilmek için neler gereklidir? Yazılımsal ve fikirsel olarak nelere ihtiyaç vardır? Sadece teorik olarak JAVA dilini bilmek yeter mi yoksa insanın canından bezdiren kurulum aşamaları, linux, mvc disiplini, en az bir framework ve gerekli araçların da (artık bu saatten sonra teorinin yetmeyeceğini anlamışsınızdır) öğrenilmesi biliyorum diyebilmeye yetecek mi?

.net frameworkune aşina, webde 2-3 yıl asp.net olsun .php olsun javascripti olsun deneyimler kazanan insanlar javaya ne kadar alışabilir? Ve daha birçok soru var aklımda cevaplanmayı bekleyen…


01.01.2015
Geçtiğimiz yılda java dili ve ortamı için önemli adımlar attım. Biraz anlatmak kendim için de iyi olacaktır. Hemen başlıyorum,
Geçtiğimiz sene Spring Framework’un kabiliyetlerine göz attım. Bunun için internette yabancı kaynaklı birçok pdf var. Bunlara boş vakitlerde göz gezdirerek Spring ile neler yapılabilir, genel olarak bahsetmek gerekirse notasyon yönetimi ne fark ve fayda sağlar, Spring Framework hangi ortamlarda kullanılabilir, MVC managment’i nasıldır bunları gördüm.
Bir örnekle; android için, web ortamı ve desktop ortamı için yazdığınız kodu Spring ile yönetebilirsiniz. Veritabanı için hazır kütüphaneleri kolaylıkla kullanabilir, Spring mvc & hibernate ile kurumsal projelere ayak uyduracak kodlar yazabilirsiniz.
Gerçekten de etkilendim. Java ortamı, Spring Framework & Yeteneklerini kullanabilen geliştiricileri kendine bağlıyor. Java, üzerine uzmanlaşıp onunla ömür boyu yaşamaya değer bir dil ve ortam sağlamış. Kod yazmaktan zevk alan insan daha ne ister ki! Bu aşık eder insanı kendine.

“Kurumsal işleri için Java kullanılır” sözünü java ile geçirdiğim süre içinde değerlendirdiğimde her şeyin bu ortamda yıllar önce temelinin atıldığını, bir düzenin kurulduğunu gördüm. Zor işlerin java ile başarıldığını gördüğümde, Jvm’in yeteneklerini, jvm’in big data managment projelerinde sağladığı esneklikleri gördümde “işte aradığım bu” dedim.

Hani şu beğenmediğimiz 200 – 300 mb’lık Eclipse var ya, öyle yeteneklere sahip olabiliyor ki .Net Visual Studiodan daha eğlenceli olabiliyor! Projelerin çoklu geliştirici desteği, repository ve code history yönetimi, -her konuda- bağımsızlık, testler (testler çok önemli. Ayrı başlıkta bunun önemine değinmeyi planlıyorum), taşınabilirlik, kütüphane yönetimi, mocking, dakikalar içinde service yazmak gibi konularının önemli olduğu projelerde (kısaca kurumsal ve büyük projelerde 🙂 ) java ve ortamı kullanılmalı. .Net artık benim için bir alternatif. Bundan eminim. .Net ortamı için Microsoft Foundation Server ve Cloud Development için Azure (bunların registration süreci bile insanı boğuyor) gerekiyorsa JAVA tarafında da elbet bir karşılığı var ve kullandığımız ortam; yıllar önce okulda Java dilinde ekrana “hello sefer” yazıp kapattığımız Eclipse ortamı …